Yacc 语法产生不正确的终端
Yacc grammar producing incorrect terminal
我一直在研究一个业余编译器,在解析阶段使用 lex 和 yacc。这对大多数事情来说都很好,但是当我添加 if 语句时,符号的生产规则现在给出堆栈上的前一个(或下一个?)项目而不是所需的符号值。
下面给出了语法,希望不相关的规则被删除:
%{
...
%}
%define parse.error verbose
%token ...
%%
Program:
Function { root->addChild();}
;
Function:
Type Identifier '|' ArgumentList '|' StatementList END
{ $$ = new FunctionDef(, , , ); }
/******************************************/
/* Statements and control flow ************/
/******************************************/
Statement:
Expression Delimiter
| VariableDeclaration Delimiter
| ControlFlowStatement Delimiter
| Delimiter
;
ControlFlowStatement:
IfStatement
;
IfStatement:
IF Expression StatementList END { $$ = new IfStatement(, ); }
| IF Expression StatementList ELSE StatementList END { $$ = new IfStatement(, , );}
;
VariableDeclaration:
Type Identifier { $$ = new VariableDeclaration(, );}
| Type Identifier EQUALS Expression { $$ = new VariableDeclaration(, , );}
;
StatementList:
StatementList Statement { ->addChild(); }
| Statement { $$ = new GenericList(); }
;
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, ); }
| Value DECREMENT { $$ = new UnaryExpression(UNARY_POSTDEC, ); }
| Value '(' ')' { $$ = new FunctionCall(, NULL); }
| Value '(' ExpressionList ')' { $$ = new FunctionCall(, ); }
| 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 ')' { $$ = ; }
| '[' ExpressionList ']' { $$ = ;}
;
LambdaFunction:
...
%%
我无法弄清楚控制流代码可以使符号如何:
规则匹配 lex 定义中未归类为符号的内容:
symbol [a-zA-Z_]+(alpha|digit)*
...
{symbol} {return SYMBOL;}
非常感谢了解 yacc 和一般语法的人提供的任何帮助。如有必要,还可以显示它解析的语法示例文件。
谢谢!
您不能指望 yytext
在 flex 动作之外的价值。
Bison 语法通常在决定如何继续之前读取先行标记,因此在 bison 操作中,yytext
已经被先行标记的标记值替换。 (不过,您也不能指望这一点:有时不需要先行标记。)
因此您需要在 flex 操作 returns 之前制作 yytext
的副本,并通过将其放入 yylval
语义联合来使该副本可用于 bison 语法。
看到这个bison FAQ entry
顺便说一下,您的 flex 文件中的以下片段是不正确的:
symbol [a-zA-Z_]+(alpha|digit)*
那个正则表达式中,alpha
和digit
只是普通的字符串,所以和[a-zA-Z_]+("alpha"|"digit")*
是一样的,意思就是会匹配,比如a_digitdigitdigit
但不是 a_123
。 (如果没有 +
之后的部分,它会匹配 a_digitdigitdigit
,所以我认为这不是您的意图。)
总的来说,我认为使用Posix字符类比手写字符类或定义符号更好,所以我会写成[=28] =]
symbol [[:alpha:]_]([[:alnum:]_]*[[:alnum:]])?
假设您的意图是一个符号可以以下划线开头但不能以下划线结尾,并且可以以数字结尾但不能以数字开头。使用 Posix 字符 类 要求您使用正确的语言环境执行 flex -- 几乎可以肯定是 C 语言环境 -- 但是 字符范围 也是如此,所以什么都没有使用自我记录 Posix 类.
丢失
(当然,我不知道你对 {alpha}
和 {digit}
的定义是什么,但在我看来它们与 [[:alpha:]]
和 [[:digit:]]
,在这种情况下它们是多余的,或者不同于 Posix 类,在这种情况下它们与 reader 混淆。)
我一直在研究一个业余编译器,在解析阶段使用 lex 和 yacc。这对大多数事情来说都很好,但是当我添加 if 语句时,符号的生产规则现在给出堆栈上的前一个(或下一个?)项目而不是所需的符号值。
下面给出了语法,希望不相关的规则被删除:
%{
...
%}
%define parse.error verbose
%token ...
%%
Program:
Function { root->addChild();}
;
Function:
Type Identifier '|' ArgumentList '|' StatementList END
{ $$ = new FunctionDef(, , , ); }
/******************************************/
/* Statements and control flow ************/
/******************************************/
Statement:
Expression Delimiter
| VariableDeclaration Delimiter
| ControlFlowStatement Delimiter
| Delimiter
;
ControlFlowStatement:
IfStatement
;
IfStatement:
IF Expression StatementList END { $$ = new IfStatement(, ); }
| IF Expression StatementList ELSE StatementList END { $$ = new IfStatement(, , );}
;
VariableDeclaration:
Type Identifier { $$ = new VariableDeclaration(, );}
| Type Identifier EQUALS Expression { $$ = new VariableDeclaration(, , );}
;
StatementList:
StatementList Statement { ->addChild(); }
| Statement { $$ = new GenericList(); }
;
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, ); }
| Value DECREMENT { $$ = new UnaryExpression(UNARY_POSTDEC, ); }
| Value '(' ')' { $$ = new FunctionCall(, NULL); }
| Value '(' ExpressionList ')' { $$ = new FunctionCall(, ); }
| 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 ')' { $$ = ; }
| '[' ExpressionList ']' { $$ = ;}
;
LambdaFunction:
...
%%
我无法弄清楚控制流代码可以使符号如何: 规则匹配 lex 定义中未归类为符号的内容:
symbol [a-zA-Z_]+(alpha|digit)*
...
{symbol} {return SYMBOL;}
非常感谢了解 yacc 和一般语法的人提供的任何帮助。如有必要,还可以显示它解析的语法示例文件。
谢谢!
您不能指望 yytext
在 flex 动作之外的价值。
Bison 语法通常在决定如何继续之前读取先行标记,因此在 bison 操作中,yytext
已经被先行标记的标记值替换。 (不过,您也不能指望这一点:有时不需要先行标记。)
因此您需要在 flex 操作 returns 之前制作 yytext
的副本,并通过将其放入 yylval
语义联合来使该副本可用于 bison 语法。
看到这个bison FAQ entry
顺便说一下,您的 flex 文件中的以下片段是不正确的:
symbol [a-zA-Z_]+(alpha|digit)*
那个正则表达式中,alpha
和digit
只是普通的字符串,所以和[a-zA-Z_]+("alpha"|"digit")*
是一样的,意思就是会匹配,比如a_digitdigitdigit
但不是 a_123
。 (如果没有 +
之后的部分,它会匹配 a_digitdigitdigit
,所以我认为这不是您的意图。)
总的来说,我认为使用Posix字符类比手写字符类或定义符号更好,所以我会写成[=28] =]
symbol [[:alpha:]_]([[:alnum:]_]*[[:alnum:]])?
假设您的意图是一个符号可以以下划线开头但不能以下划线结尾,并且可以以数字结尾但不能以数字开头。使用 Posix 字符 类 要求您使用正确的语言环境执行 flex -- 几乎可以肯定是 C 语言环境 -- 但是 字符范围 也是如此,所以什么都没有使用自我记录 Posix 类.
丢失(当然,我不知道你对 {alpha}
和 {digit}
的定义是什么,但在我看来它们与 [[:alpha:]]
和 [[:digit:]]
,在这种情况下它们是多余的,或者不同于 Posix 类,在这种情况下它们与 reader 混淆。)