Lex & YACC 4
http://d.hatena.ne.jp/longicorn/20080917#p1の続き
http://d.hatena.ne.jp/longicorn/20080923#p1で本が無かったのでネットで勉強を続けてみる。
取りあえず簡単な構文解析。
フォーマットは
hoge = 111
という「変数=数字」の形式を想定してみる
parse.l
%{ #include <stdio.h> #include <string.h> #include "parse.tab.h" void yyerror(const char *str) { fprintf(stderr,"error: %s\n",str); } int yywrap(void) { return 1; } %} %% \= return EQUAL; [[:alpha:]]+ yylval=(int)strdup(yytext); return STRING; [[:digit:]]+ yylval=atoi(yytext); return NUMBER; \n /* 改行は無視 */; [:blank:]+ /* ホワイトスペースは無視 */; %%
parse.y
%{ #include <stdio.h> #include <stdlib.h> #ifdef DEBUG extern int yydebug; #endif %} %token EQUAL %token STRING %token NUMBER %% command : STRING EQUAL NUMBER { printf("%s = %d\n", (char*)$1, $3); free((char*)$1); } ; %% extern FILE *yyin; int main(int argc, char **argv){ FILE *fp; #ifdef DEBUG printf("defined YYDEBUG\n"); yydebug = 1; #endif if(argc == 2){ printf("%s\n", argv[1]); fp = fopen(argv[1], "r"); if(fp == NULL){ yyin = stdin; } yyin = fp; } else{ yyin = stdin; } if(yyparse() != 0){ fprintf(stderr, "yyparse() error\n"); } fclose(fp); return 0; }
PROGRAM = parse OBJS = parse.tab.o lex.yy.o CR = CC = $(CR)gcc DEBUG = -DYYDEBUG -UDEBUG #for debug #DEBUG = -DYYDEBUG -DDEBUG CFLAGS = -Werror -DYYERROR_VERBOSE $(DEBUG) LEX = flex LFLAGS = YACC = bison YFLAGS = -d $(PROGRAM) : $(OBJS) $(CC) $(CFLAGS) -o $@ $? lex.yy.o : lex.yy.c parse.tab.o : parse.tab.c lex.yy.c : parse.l $(LEX) $(LFLAGS) $? parse.tab.c : parse.y $(YACC) $(YFLAGS) $? clean : rm -f core $(PROGRAM) $(OBJS) lex.yy.c parse.tab.[ch]
新しいのはMakefileの追加。
とりあえずこれでパースの結果をprintfで出力できる。
ただ、問題点が1つ。
parse.lでstrdupを使って文字列をyylvalに取得しているけど、yylvalが実はint型。
ネットの情報によると、
#define YYSTYPE char *
すればいいらしいんだけど、yylvalとstrdup(3)の型が違うと怒られてコンパイルできない。
取りあえず、int型にキャストで逃げてなんとかコンパイル成功。
けどなんとか正攻法でコンパイルしたいよな。
どうすればいいんだか。
追記:
バグ発見。
2行入力でセグった。