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行入力でセグった。