我已经在爱好编译器上工作了一段时间,使用lex和yacc进行解析阶段。这对大多数事情都很好,但是当我在if语句中添加时,符号的生成规则现在给出了堆栈上的前一个(或下一个?)项而不是所需的符号值。
语法在下面给出了希望无关的规则:
%{
...
%}
%define parse.error verbose
%token ...
%%
Program:
Function { root->addChild($1);}
;
Function:
Type Identifier '|' ArgumentList '|' StatementList END
{ $$ = new FunctionDef($1, $2, $4, $6); }
/******************************************/
/* Statements and control flow ************/
/******************************************/
Statement:
Expression Delimiter
| VariableDeclaration Delimiter
| ControlFlowStatement Delimiter
| Delimiter
;
ControlFlowStatement:
IfStatement
;
IfStatement:
IF Expression StatementList END { $$ = new IfStatement($2, $3); }
| IF Expression StatementList ELSE StatementList END { $$ = new IfStatement($2, $3, $5);}
;
VariableDeclaration:
Type Identifier { $$ = new VariableDeclaration($1, $2);}
| Type Identifier EQUALS Expression { $$ = new VariableDeclaration($1, $2, $4);}
;
StatementList:
StatementList Statement { $1->addChild($2); }
| Statement { $$ = new GenericList($1); }
;
Delimiter:
';'
| NEWLINE
;
Type:
...
Expression:
...
PostfixExpression:
Value '[' Expression ']' { std::cout << "TODO: indexing operators ([ ])" << std::endl;}
| Value '.' SYMBOL { std::cout << "TODO: member access" << std::endl;}
| Value INCREMENT { $$ = new UnaryExpression(UNARY_POSTINC, $1); }
| Value DECREMENT { $$ = new UnaryExpression(UNARY_POSTDEC, $1); }
| Value '(' ')' { $$ = new FunctionCall($1, NULL); }
| Value '(' ExpressionList ')' { $$ = new FunctionCall($1, $3); }
| Value
;
Value:
BININT { $$ = new Integer(yytext, 2); }
| HEXINT { $$ = new Integer(yytext, 16); }
| DECINT { $$ = new Integer(yytext); }
| FLOAT { $$ = new Float(yytext); }
| SYMBOL { $$ = new Symbol(yytext); }
| STRING { $$ = new String(yytext); }
| LambdaFunction
| '(' Expression ')' { $$ = $2; }
| '[' ExpressionList ']' { $$ = $2;}
;
LambdaFunction:
...
%%
我无法弄清楚控制流代码可以使符号: 规则匹配从lex定义中未被归类为符号的东西:
symbol [a-zA-Z_]+(alpha|digit)*
...
{symbol} {return SYMBOL;}
任何了解yacc和语法的人都会非常感激。如果需要,还可以显示它解析的语法的示例文件。
谢谢!
答案 0 :(得分:1)
您不能指望在flex动作之外yytext
的值。
Bison语法通常会在决定如何继续之前读取前瞻标记,因此在野兔操作中,yytext
已被替换为先行标记的标记值。 (不过你也不能指望:有时候不需要先行令牌。)
因此,您需要在flex操作返回之前制作yytext
的副本,并通过将其放入yylval
语义联合中使该副本可用于bison语法。
请参阅此bison FAQ entry
顺便说一句,flex文件中的以下代码段不正确:
symbol [a-zA-Z_]+(alpha|digit)*
在该正则表达式中,alpha
和digit
只是普通字符串,因此它与[a-zA-Z_]+("alpha"|"digit")*
相同,这意味着它将匹配,例如{{1}但不是a_digitdigitdigit
。 (如果没有a_123
之后的部分,它会匹配a_digitdigitdigit
,所以我认为这不是你的意图。)
总的来说,我认为使用Posix字符类比使用手写字符类或定义符号更好,所以我会把它写成
+
假设您的意图是符号可以开始但不以下划线结束,并且结束但不以数字开头。使用Posix字符类要求您使用正确的语言环境执行flex - 几乎可以肯定是C语言环境 - 但是也要执行字符范围,因此使用自我记录的Posix类不会丢失任何内容
(当然,我不知道您对symbol [[:alpha:]_]([[:alnum:]_]*[[:alnum:]])?
和{alpha}
的定义是什么,但在我看来,它们与{digit}
和{{1}相同在这种情况下,它们是冗余的,或者与Posix类不同,在这种情况下它们会让读者感到困惑。)