C言語アルゴリズム-字句解析
前へ 目次へ 次へ 

2 字句解析 (2)

C言語専用の字句解析関数get_token_cを作成する。

 関数get_tokenでは記号は1文字ずつ取り出される。上の実行例のようにコメント文をはさむ/*と*/もバラバラに取り出されている。/*、*/として取り出せた方が関数strcmpで比較できて便利である。また、比較演算子も同様である。このように、記号が連続した演算子等を次に示す。

++, --, ==, !=, >=, <=, &&, ||, >>, <<, ->, /*, */

 ここでは、関数get_tokenを利用してC言語専用の字句解析関数get_token_cを作成する。処理の手順を簡単に説明すると次のようになる。
 上の記号の1文字目が現れたら再度get_tokenし、その記号に対応する2文字目かどうかを判定する。
 該当する連続記号であれば、1番目と2番目の記号を連結して変数tokenに格納する。該当する連続記号でなければ2番目を関数unget_tokenで戻し、1番目を変数tokenに格納する。

[gt_c.c]

 1:
 2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "gettoken.h"

char *c_get_token(void)
{
    char    token_1[STR_MAX];
    char    flag = 0;           /* 連続記号用フラグ */

    if(*get_token() == '\0')        /* 1番目のトークン取得 */
        return(token);
    strcpy(token_1, token);         /* token_1に保存 */
    if(*get_token() == '\0'){       /* 2番目のトークン取得 */
        strcpy(token, token_1);
        return(token);
    }
    switch(*token_1){
        case '+':                   /* ++, &&, ||, == */
        case '&':
        case '|':
        case '=':
            if(*token_1 == *token)  /* 1番目と2番目が同じ */
                flag = 1;
            break;
        case '<':                   /* <=, >=, <<, >> */
        case '>':
            if(*token_1 == *token || *token == '=') /* 同じか=である */
                flag = 1;
            break;
        case '-':
            if(*token_1 == *token || *token == '>') /* 同じか>である */
                flag = 1;
            break;
        case '!':               /* != */
            if(*token == '=')       /* 2番目が=である */
                flag = 1;
            break;
        case '/':               /*  / *  */
            if(*token == '*')       /* 2番目が*である */
                flag = 1;
            break;
        case '*':               /*  * /  */
            if(*token == '/')       /* 2番目が/である */
                flag = 1;
            break;
    }
    if(flag){
        strcat(token_1, token);     /* トークンの連結 */
        strcpy(token, token_1);     /* tokenに格納 */
    }else{
        unget_token(token);         /* 2番目を戻す */
        strcpy(token, token_1);     /* 1番目をtokenに格納 */
    }
    return(token);
}

void main(void)
{
    FILE    *bf;
    char    file[80];       /* ファイル名 */

    printf("ファイル名 : ");  /* プロンプト表示 */
    gets(file);             /* ファイル名入力 */
    if((bf = fopen(file, "r")) == NULL){    /* ファイルオープン */
        printf("ファイルがオープンできない\n");
        exit(1);    /* 強制終了 */
    }
    while(fgets(gt_line, STR_MAX, bf) != NULL){    /* 1行読み込み */
        while(1){
            c_get_token();
            if(token[0] == '\0')    /* 1行分終了 */
                break;
            if(*token == '\n')
                printf("(\\n)");    /* 改行コード */
            else
                printf("(%s) ", token);     /* 表示 */
        }
        printf("\n");
    }
    fclose(bf);         /* ファイルクローズ */
}

 ここでは、文字の判定にswitch文を使用している。これは、例えば20〜23行目の部分をif文にすると次のように非常に長くなるためである。

if(*token_1 == '+' || *token_1 == '&' || *token_1 == '|' || *token_1 == '=')

 12行目で、1番目のトークンを取り出し、14行目で変数token_1に格納する。
 15行目で、2番目のトークンを取り出している。
 19〜48行で、該当する連続記号であれば、変数flagを1にする。
 該当する連続記号であれば50,51行が実行され、該当しなければ53,54行が実行される。例えば、!=の処理は、次のようになる。
gettoken c
 このように、関数get_tokenをベースに各種の言語に合わせた字句解析ルーチンを作成することができる。


練習問題2-1 C言語専用の字句解析関数get_token_cに16進数の処理を追加しなさい。 (ren2-1.c)
 C言語での16進数表記は、先頭に0xまたは0Xを付けて表す。例えば、0x12は関数get_tokenでは0とx12に分かれて取り出される。資料2.2のプログラムに16進数が正しく取り出せる処理を追加しなさい。


前へ 目次へ 次へ 
Copyright © 2001 Hiroshi Masuda 

 

 

inserted by FC2 system