C言語関係掲示板

過去ログ

No.1075 トークンを演算する

[戻る] [ホームページ]
No.14087

解析
投稿者---GASS(2004/05/18 21:51:45)


以下のプログラムを、たとえば
>   123 *234
B:   .
N:123.
B: .
O:*.
N:234.
H:
.
28782
>


とやりたいのですが、途中まで書いて行き詰まりました。
どなたか教えてください。お願いします。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAXLENGTH 256

int Get_Token(char *, char *);
int Is_Operator(char);

int main(void)
{
    char *ptr;
    char line[MAXLENGTH], token[MAXLENGTH];
    int classToken;
    
    printf(">");
    while(fgets(line, MAXLENGTH, stdin)){
        if(line[0] == '.'){
            exit(0);
        }
        ptr = line;
        while (strlen(ptr) > 0) {
          classToken =  Get_Token(ptr, token);
          printf("%c:%s.\n", classToken, token);
            ptr = ptr + strlen(token);
        }
    }
    return 0;
}

int Get_Token(char *line, char *token)
{
    int state;  /* 状態変数 */
    char *ptr;  /* 文字列lineの中で現在見ているところ */
    char *head; /* 今切り出しているトークンの先頭を覚えておくところ */
    
    state = 'I'; /* 最初は初期(Initial)状態にする */
    ptr = line;  /* 受け取った文字列lineの先頭から見始める */
    
    while(1){
        switch (state) {            /* もし現在の状態が... */
          case 'I':                   /* 初期(Initial)状態で... */
            if (islower(*ptr)) {      /* いま見ている文字が英小文字だったら... */
                state = 'V';            /* 現在の状態を変数(Variable)モードにして */
                head = ptr;             /* この変数トークンの先頭を覚えておき */
                ptr++;                  /* 次の文字へ移動する */
                if (strlen(ptr) > 0) {  /* まだ変数トークンの途中であれば */
                    continue;             /* 次の文字の処理に移る */
                } else {                /* この変数トークンが1文字のものであれば */
                    strncpy(token, head, ptr - head); /* token にそれをコピーして */
                    token[ptr - head] = '\0';    /* その最後に'\0'をつける */
                    return 'V';           /* いま読んだトークンは変数であったと返す */
                }
            } else if (isdigit(*ptr)) {
                state = 'N';
                head = ptr;
                ptr++; 
                if (strlen(ptr) > 0) {  
                    continue;            
                } else {                
                    strncpy(token, head, ptr - head); 
                    token[ptr - head] = '\0';   
                    return 'N';           
                }
            
            } else if (Is_Operator(*ptr)) { /* いま見ている文字が演算子だったら... */
                state = 'O';
                head = ptr;
                if (strlen(ptr) > 0) {  
                    continue;             
                } else {     
                    strncpy(token, head, ptr - head); 
                    token[ptr - head] = '\0';   
                    return 'O';           
                }  
            
            } else if (*ptr == '='){
                strcpy(token, "=");      
                       return 'S';             
            } else if (*ptr == '.') { /* いま見ている文字が'.'だったら... */
                return 'T';
            } else if (*ptr == ' ') { /* いま見ている文字が空白だったら... */
                state = 'B';
                head = ptr;
                ptr++;
                if (strlen(ptr) > 0) {  
                    continue;            
                } else {                
                    strncpy(token, head, ptr - head); 
                    token[ptr - head] = '\0';   
                    return 'B';           
                }   
            } else if (*ptr == '\n') {/* いま見ている文字が改行だったら... */    
                    return 'H';
                
            } else {                  /* いま見ている文字が上記以外だったら... */
                return 'E';
            }
            
          case 'V':     /* 変数(Variable)状態で... */
           
          case 'N':     /* 数値(Numeric)状態で... */
            
          case 'B':     /* 空白文字列(Blank)状態で... */
           
        }
    }
}
    
int Is_Operator(char ptr)
{
    return ptr == '+' || ptr == '-' || ptr == '*' || ptr =='/';
}




No.14090

Re:解析
投稿者---かずま(2004/05/19 14:14:21)


> とやりたいのですが、途中まで書いて行き詰まりました。
行き詰るはずです。'V' や 'S' や 'T' って何なの?
仕様を明確にしてくれないとプログラムは書けません。
質問にあった入出力例を満たすプログラムならこんなもんでしょうか。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int get_token(const char *p, char *token)
{
    int c = *p;
    if (c == '\n') { *token++ = c; *token = 0; return 'H'; }
    if (strchr("+-*/", c)) { *token++ = c; *token = 0; return 'O'; } 
    if (c == ' ') {
        do { *token++ = c; c = *++p; } while (c == ' ');
        *token = 0;
        return 'B';
    }
    if (isdigit(c)) {
        do { *token++ = c; c = *++p; } while (isdigit(c));
        *token = 0;
        return 'N';
    }
    *token++ = c; *token = 0;
    return 'E';
}

int main(void)
{
    char buf[1024], token[1024], *p;
    int class, num[2], op = 0, i = 0;

    while (printf(">"), fgets(buf, sizeof buf, stdin) && *buf != '.') {
        for (p = buf; *p; p += strlen(token)) {
            class = get_token(p, token);
            printf("%c:%s.\n", class, token);
            if (class == 'N' && i < 2) num[i++] = atoi(token);
            if (class == 'O') op = *token;
        }
        if (i == 2)
            switch (op) {
              case '+': printf("%d\n", num[0] + num[1]); break;
              case '-': printf("%d\n", num[0] - num[1]); break;
              case '*': printf("%d\n", num[0] * num[1]); break;
              case '/': printf("%d\n", num[0] / num[1]); break;
            }
    }
    return 0;
}



No.14092

Re:解析
投稿者---かずま(2004/05/19 14:57:50)


訂正です。

    int class, num[2], op = 0, i = 0;
と
    if (class == 'N' && i < 2) num[i++] = atoi(token);
 
の 2 を 3にする。

while ループの中の for ループの前に、i = 0; を置く。



No.14098

Re:解析
投稿者---GASS(2004/05/19 19:36:42)



>>行き詰るはずです。'V' や 'S' や 'T' って何なの?
>>仕様を明確にしてくれないとプログラムは書けません。

すみません、コメントと一緒に改めてソースです。
仕様は1文字で構成されるトークンと2文字以上のトークンとで処理が異なります。2文字以上になる可能性のあるトークンは変数,数値,空白文字列です。だから、これらの2文字目から先を処理するために switch 文の case として 'V', 'N', 'B' が用意されています。2文字以上になる可能性のないトークン,たとえば代入演算子の'='などはすぐに処理が終るのでその場で return しています。逆に2文字以上になる可能性のあるトークンである変数の場合にも1文字のトークンというのはありえます.その場合を判断するための if 文が case 'I' のところにあるのがわかるでしょう.この変数トークンが 1文字のみで構成されると判断した場合には,その場で return し,そうでないと判断した場合には continue しています。


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAXLENGTH 256

int Get_Token(char *, char *);
int Is_Operator(char);

int main(void)
{
    char *ptr;
    char line[MAXLENGTH], token[MAXLENGTH];
    int classToken;
    
    printf(">");
    while(fgets(line, MAXLENGTH, stdin)){
        if(line[0] == '.'){
            exit(0);
        }
        ptr = line;
        while (strlen(ptr) > 0) {
          classToken =  Get_Token(ptr, token);
          printf("%c:%s.\n", classToken, token);
            ptr = ptr + strlen(token);
        }
    }
    return 0;
}

int Get_Token(char *line, char *token)
{
    int state;  /* 状態変数 */
    char *ptr;  /* 文字列lineの中で現在見ているところ */
    char *head; /* 今切り出しているトークンの先頭を覚えておくところ */
    
    state = 'I'; /* 最初は初期(Initial)状態にする */
    ptr = line;  /* 受け取った文字列lineの先頭から見始める */
    
    while(1){
        switch (state) {            /* もし現在の状態が... */
          case 'I':                   /* 初期(Initial)状態で... */
            if (islower(*ptr)) {      /* いま見ている文字が英小文字だったら... */
                state = 'V';            /* 現在の状態を変数(Variable)モードにして */
                head = ptr;             /* この変数トークンの先頭を覚えておき */
                ptr++;                  /* 次の文字へ移動する */
                if (strlen(ptr) > 0) {  /* まだ変数トークンの途中であれば */
                    continue;             /* 次の文字の処理に移る */
                } else {                /* この変数トークンが1文字のものであれば */
                    strncpy(token, head, ptr - head); /* token にそれをコピーして */
                    token[ptr - head] = '\0';    /* その最後に'\0'をつける */
                    return 'V';           /* いま読んだトークンは変数であったと返す */
                }
            } else if (isdigit(*ptr)) {
                state = 'N';
                head = ptr;
                ptr++; 
                if (strlen(ptr) > 0) {  
                    continue;            
                } else {                
                    strncpy(token, head, ptr - head); 
                    token[ptr - head] = '\0';   
                    return 'N';           
                }
            
            } else if (Is_Operator(*ptr)) { /* いま見ている文字が演算子だったら... */
                state = 'O';
                head = ptr;
                if (strlen(ptr) > 0) {  
                    continue;             
                } else {     
                    strncpy(token, head, ptr - head); 
                    token[ptr - head] = '\0';   
                    return 'O';           
                }  
            
            } else if (*ptr == '='){/* いま見ている文字が'='だったら... */
                strcpy(token, "=");   /* tokenに"="をコピーして */ 
                       return 'S';    /* いま読んだトークンは代入演算子であったと返す */        
            } else if (*ptr == '.') { /* いま見ている文字が'.'だったら... */
                return 'T';
            } else if (*ptr == ' ') { /* いま見ている文字が空白だったら... */
                state = 'B';
                head = ptr;
                ptr++;
                if (strlen(ptr) > 0) {  
                    continue;            
                } else {                
                    strncpy(token, head, ptr - head); 
                    token[ptr - head] = '\0';   
                    return 'B';           
                }   
            } else if (*ptr == '\n') {/* いま見ている文字が改行だったら... */    
                    return 'H';
                
            } else {                  /* いま見ている文字が上記以外だったら... */
                return 'E';
            }
            
          case 'V':     /* 変数(Variable)状態で... */
           
          case 'N':     /* 数値(Numeric)状態で... */
            
          case 'B':     /* 空白文字列(Blank)状態で... */
           
        }
    }
}
    
int Is_Operator(char ptr)
{
    return ptr == '+' || ptr == '-' || ptr == '*' || ptr =='/';
}