lex和yacc的使用

2018-12-23

lex和yacc的使用

起因是编译原理老师要求用这两个东西做做实验。做自己的编译器也是很好玩的事,动手搞一搞。

环境

我是win10环境,用gnu版的flex和bison(分别对应lex和yacc):

有setup就装setup,然后将俩exe添加到$env:Path方便用。

编写.l和.y文件

lex和yacc语法可以参考IBM的教程:https://www.ibm.com/developerworks/cn/linux/sdk/lex/

生成c语言源文件和头文件

win_bison -d filename.y
win_flex --wincompat filename.l

这些参数主要作用是为了生成不依赖<unistd.h>的代码,否则在win上无法编译。

VS工程

把所有生成的.h文件和.c的文件添加到项目中。然后添加第一步下载的静态库依赖,主要是GnuWin32文件夹下的libfl.a

修改地方:

  • 项目属性->链接器->常规->附加库目录->添加GnuWin32文件夹
  • 项目属性->链接器->输入->附加依赖项->添加libfl.a

build

1

嗯,还是很好玩的。

我的代码

%{
 
# include"myyacc.tab.h"
# include"opt.h"

%}
number ([0-9])+
chars [A-Za-z]
variable ${chars}+{number}*{chars}*{number}*

%%
 
"+" { return ADD; }
"-" { return SUB; }
"*" { return MUL; }
"/" { return DIV; }
"|" { return ABS; }
"(" { return OP; }
")" { return CP; }
"=" { return ASSIGN; }
"<" { return LT; }
">" { return GT; }
"#=" { return EQ; } 
"IF" { return IF; }
"if" { return IF;}
"THEN" { return THEN; }
"then" { return THEN; }
"ELSE" { return ELSE; }
"else" { return ELSE; }
 
{number} { yylval = atoi(yytext); return NUMBER; }
{variable} { yylval=hash(yytext);return VAR; }
 
\n { return EOL; }
"//".*
[ \t] { /* ignore white space */ }
. { yyerror("Unrecognized character : %c\n", *yytext); }
%%

//这个hash函数事为了做symboltable用的
int hash(char *str)
{
	int hash = 5381;
	int c;
	while (c = *str++)
	hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
	if(hash<0)
	{
		hash=-hash;
	}
	return hash%SYMTABLE_SIZE;
}
%{
 
# include <stdio.h>
# include"opt.h"
int symboltable[SYMTABLE_SIZE];	//简单起见就用数组作为符号表,哈希函数在mylex文件中
# define INTMAX 2147483647

%}
 
/* declare tokens*/
%token NUMBER
%token ADD SUB MUL DIV ABS
%token OP CP
%token EOL
%token VAR
%token ASSIGN
%token IF ELSE THEN
%token LT GT EQ
 
%%
 
line:
| line exp EOL { if($2!=INTMAX)printf("%d\n>", $2);else printf("OK\n>"); }
| line EOL { printf(">"); }
;
 
exp: factor
| exp ADD exp { $$ = $1 + $3; }
| exp SUB factor { $$ = $1 - $3; }
| exp ABS factor { $$ = $1 | $3; }
| VAR ASSIGN exp {symboltable[$1]=$3;$$=INTMAX;}
| VAR {$$=symboltable[$1];}
| IF exp THEN exp ELSE exp { if($2>0) $$=$4;else $$=$6;}
| exp LT exp {if($1<$3) $$=1; else $$=0;}
| exp GT exp {if($1>$3) $$=1; else $$=0;}
| exp EQ exp {if($1==$3) $$=1; else $$=0;}
;
 
factor: term
| factor MUL term { $$ = $1 * $3; }
| factor DIV term { $$ = $1 / $3; }
;
 
term: NUMBER
| ABS term { $$ = $2 >= 0? $2 : - $2; }
| OP exp CP { $$ = $2; }
| SUB NUMBER { $$ = -$2;}
;
 
%%
 
main()
{
	//initalize the symbol table
	for(int i=0;i<SYMTABLE_SIZE;i++)
		symboltable[i]=0;

	printf("QELang v0.0.1\t Author:@QE \n\n");
    printf(">");
    yyparse();
}
 
yyerror(char *s)
{
    fprintf(stderr, "error: %s\n", s);
	return 0;
}