1.概念yacc使用巴克斯范式(BNF)定义语法,能处理上下文无关文法(context-free)。出现在每个产生式左边(left-hand side:lhs)的符号是非终端符号,出现在产生式右边(right-hand
side:rhs)的符号有非终端符号和终端符号,但终端符号只出现在右端。 在规约过程中可能会有冲突。Yacc对此有一些缺省的处理方法,那就是使用第一个匹配的规则。 2.Yacc文件格式Yacc文件分为三部分:... definitions ... %% ... rules ... %% ... subroutines ... 3.定义部分第一部分包括标志(token)定义和C代码(用“%{”和“%}”括起来)。如在定义部分定义标志: 当运行yacc后,会产生头文件,里面包含该标志的预定义,如:
lex使用该头文件中的标志定义。Yacc调用lex的yylex()来获得标志(token),与标志对应的值由lex放在变量yylval中。yylval的类型由YYSTYPE决定,YYSTYPE缺省类型是int。如: 标志0-255被保留作为字符值,一般产生的token标志从258开始。如:
对于操作符,可以定义%left和%right:%left表示左相关(left-associative),%right表示右相关(right-associative)。可以定义多组%left或%right,在后面定义的组有更高的优先级。如: Yacc内部维持着两个栈:符号栈(parse stack)和值栈(value
stack),这两个栈始终是同步的。 改变YYSTYPE的类型。如这样定义TTSTYPE: 可以把标志(token)绑定到YYSTYPE的某个域。如: 定义一元减号符有更高的优先级的方法: 4.规则部分规则部分很象BNF语法。规则中目标或非终端符放在左边,后跟一个冒号(:),然后是产生式的右边,之后是对应的动作(用{}包含)。如: 其中,$1表示右边的第一个标记的值,$2表示右边的第二个标记的值,依次类推。$$表示规约后的值。 5.第三部分该部分是函数部分。当yacc解析出错时,会调用函数yyerror(),用户可自定义函数的实现。main函数是调用yacc解析入口函数yyparse()。6.递归的处理递归处理有左递归和右递归。左递归形式: 右递归形式: 使用右递归时,所有的项都压入堆栈里,才开始规约;而使用左递归的话,同一时刻不会有超过三个项在堆栈里。 所以,使用左递归有很大的优势。 7.If-Else的冲突当有两个IF一个ELSE时,该ELSE和哪个IF匹配是一个问题。有两中匹配方法:与第一个匹配和与第二匹配。现代程序语言都让ELSE与最近的IF匹配,这也是yacc的缺省行为。虽然yacc行为正确,但为避免警告,可以给IF-ELSE语句比IF语句更高的优先级: |
|