数式の評価を原始的に #11
字句とは、1個以上の数字列(非負整数)か、数字と' 'と'\t'以外の1個の文字か、入力の終端か、である。
入力の終端は文字そのものではなく、これ以上入力がないことを示すためのシンボルである。
この字句の定義に合わせてTokenの定義を変更する。
#define TOKEN_TYPE_EOF 256 #define TOKEN_TYPE_INTEGER 257 typedef struct { int type; char *value; } Token;
入力の一文字読み戻し用の情報を加えるためにLexerも少し変更。
typedef struct { Token token; size_t buffer_size; char *buffer; Reader *reader; int internal_prepared_reader; int pre_read; int has_pre_read; } Lexer;
その初期化のための一文を追加。
void lexer_init_with_reader(Lexer *lexer, Reader *reader) { lexer->buffer = malloc(LEXER_BUFFER_INIT_SIZE); if (lexer->buffer == NULL) { perror("fail to allocate Lexer internal buffer"); exit(1); } lexer->buffer_size = LEXER_BUFFER_INIT_SIZE; lexer->reader = reader; lexer->internal_prepared_reader = 0; lexer->has_pre_read = 0; }
そして字句切り出しの関数を変更。
Token *lexer_next_token(Lexer *lexer) { for (;;) { int c; if (lexer->has_pre_read) { c = lexer->pre_read; lexer->has_pre_read = 0; } else { c = lexer->reader->any.get(lexer->reader); } if (c == EOF) { lexer->token.type = TOKEN_TYPE_EOF; break; } if (c == ' ' || c == '\t') continue; if (isdigit(c)) { size_t i = 0; do { lexer->buffer[i++] = c; if (i == lexer->buffer_size - 1) { size_t s = lexer->buffer_size + LEXER_BUFFER_INCREASE; char *b = realloc(lexer->buffer, s); if (b == NULL) { perror("fail to re-allocate Lexer internal buffer"); exit(1); } lexer->buffer_size = s; lexer->buffer = b; } c = lexer->reader->any.get(lexer->reader); } while (isdigit(c)); lexer->buffer[i] = '\0'; lexer->token.type = TOKEN_TYPE_INTEGER; lexer->token.value = lexer->buffer; lexer->pre_read = c; lexer->has_pre_read = 1; break; } else { lexer->token.type = c; break; } } return &lexer->token; }
最後にLexerを使って字句切り出しの結果を表示するmain関数。
int main(int argc, char *argv[]) { Lexer lexer; Reader reader; int eof = 0; if (argc > 1) { strreader_init(&reader, argv[1]); lexer_init_with_reader(&lexer, &reader); } else { lexer_init(&lexer); } while (! eof) { Token *token = lexer_next_token(&lexer); switch (token->type) { case TOKEN_TYPE_EOF: puts("[type=EOF]"); eof = 1; break; case TOKEN_TYPE_INTEGER: printf("[type=INTEGER,value=%s]\n", token->value); break; default: if (isprint(token->type)) { printf("[type=%c]\n", token->type); } else { printf("[type=0x%02x]\n", token->type); } } } lexer_fin(&lexer); return 0; }