简记
- wc程序可以读取多个文件,通过判断main函数参数(argc数量)来控制读取多个文件
- √makefile写法 p20
- 语法分析中的优先级与循环原理还待理解 p159
- √识别注释原理 p46
- 移进:把获取到的记号压入堆栈
- 规约:把满足规则的所有记号弹栈 p55
- %token <变量名> token名---------将token的值保存在<>中的变量中
- %type <变量名> 非终结符----------将<>变量的值赋给非终结符 p59
- 移进/规约冲突和操作符优先级 p63
- √flex元字符 p137
- √奇技淫巧:可已改写yyerror函数以显示错误的行号和字符/字符串
flex元字符
字符 | description | ex |
---|---|---|
. | 匹配除换行符’\n’外所有字符 | |
[] | 匹配括号内的任意字符 | |
* | 匹配零个或多个紧接在前面的表达式 | 例如a.*z匹配以a开头以z结尾的所有单词 |
+ | 匹配至少一个紧接在前面的表达式 | |
? | 匹配零个或一个紧接在前面的表达式 | -?[0-9]可匹配负数 |
{} | 前面表达式可重复次数 | {1,}与+的意思一致 |
\ | 转义字符 | |
() | 把一系列正则表达式组合在一起,+*?只影响其左边表达式 | (ab|cd)?ef |
| | 匹配前面或后面的正则表达式 | twelve|12匹配这俩 |
“…” | 根据字面意思匹配引号内的字符除了反义字符 | |
/ | 匹配斜线前的表达式但是要求斜线后紧跟一表达式 | 0/1只会匹配01中的0不会匹配02中的0 |
^ | 作为正则表达式的首字符时匹配一行的开始;也被用于方括号中代表补集,其他情况无特殊含义 | |
$ | 作为正则表达式的最后一字符时匹配一行的结束,其他情况无特殊意义 | 在表达式末尾与/\n有相同意义 |
<<EOF>> | 特殊模式匹配文件末尾 |
flex&bison的makefile写法
例:
calc: calc.l calc.y
flex calc.l
bison -d calc.y
cc -o $@ calc.tab.c lex.yy.c -lfl
$@是Makefile的自动化变量,代表目标文件calc
匹配c/c++代码注释
例:
%%
"/*" { BEGIN(COMMENT); }
<COMMENT>"*/" { BEGIN(INITIAL); }
<COMMENT>([^*]|\N)+|.
<COMMENT><<EOF>> { printf("%s:%d Unterminated comment\n",curfilename,yylineno);return 0;}
"//".*\n
%parse-param
通常调用yyparse()函数是不需要参数的,但是如果需要从其他程序中导入一些信息,可以使用全局变量:
%parse-param {char *modulename}
%parse-param {int intensity}
...
这样就可以直接调用yyparse(“modulename”,num)来使用,将全局变量作为参数导入语法分析器。
改写yyerror函数以显示错误的行号和字符/字符串
void yyerror(char *);
extern char* yytext;
extern int yylineno;
void yyerror(char *s) {
printf("%d: %s at %s\n",yylineno,s,yytext);
}
规则部分的动作
动作(action)是bison匹配语法中一条规则执行时的C代码,必须是C语言的复合语句,例:
date: month '/' day '/' year { printf("date found"); } ;
date: month '/' day '/' year { printf("date %d-%d-%d",$1,$2,$3); } ;
没有语义的规则使用默认动作:
{ $$ = $1; }
递归规则
主要规则只要记住任何递归规则或者交互递归规则组里的每个规则都必须至少有一条非递归的分支(不指向自身)。
bison处理左递归比右递归有效率(所以基本上只用左递归就可以了)
*个人理解的一些移进规约
例程:
%%
command : exp {printf("%d/n",$1);}
| QUOTE {printf("this is a quote\n");}
;
exp: exp PLUS term {$$ = $1 + $3;}
|exp MINUS term {$$ = $1 - $3;}
|term {$$ = $1;}
;
term : term TIMES factor {$$ = $1 * $3;}
|term DIVIDE factor {$$ = $1/$3;}
|factor {$$ = $1;}
;
factor : INTEGER {$$ = $1;}
| LP exp RP {$$ = $2;}
;
%%
- 输入: 3 + 5
移进 3(number) > INTEGER
规约 INTEGER > factor > term > exp
移进 +(plus) > PLUS
规约 PLUS
移进 5
规约 INTEGER > factor > term
规约 exp PLUS term > exp > command