【发布时间】:2018-11-05 22:52:10
【问题描述】:
我有一个关于我用 C 语言编写的解析器的问题。假设使用左递归(为运算符提供左关联性),然后以后缀表示法返回表达式。专门针对我的 Expr 和 Term 规则。目前我遇到了一个我认为这不会发生的问题。这是我的语法:
extern int yylex(); /* The next token function. */
extern char *yytext; /* The matched token text. */
extern int yyleng; /* The token text length. */
void yyerror(char *s);
#define YYSTYPE long /* 64 bit so can hold pointer and int */
%}
// These token definitions populate y.tab.h
// Single character tokens are their own token numbers (e.g. scanner returns
// the value ';' for the semicolon token)
%token INT_TOK 1
%token CHR_TOK 2
%token ASSIGN_TOK 3
%token INTLIT_TOK 4
%token IDENT_TOK 5
%%
Prog : IDENT_TOK '{' StmtSeq '}' { $$ = (long) strdup(yytext); } ;
StmtSeq : Stmt ';' StmtSeq ;
StmtSeq : ;
Assign : LHS ASSIGN_TOK Expr { printf("%s =\n",(char *)$1); } ;
LHS : IDENT_TOK { $$ = (long) strdup(yytext); } ;
Stmt : Decl;
Stmt : Assign;
Decl : Type IDLst;
Type : INT_TOK;
Type : CHR_TOK;
IDLst : IDENT_TOK MLst;
MLst : ',' IDLst;
MLst : ;
Expr : Term MExpr;
MExpr : AddOp Term MExpr { printf("%s ",(char *)$1); } ;
MExpr : ;
Term : Factor MTerm;
MTerm : MultOp Factor MTerm { printf("%s ",(char *)$1); } ;
MTerm : ;
Factor : '(' Expr ')';
Factor : '-' Factor;
Factor : INTLIT_TOK { printf("%s ",yytext); }
Factor : IDENT_TOK { printf("%s ",yytext); }
AddOp : '-' { $$ = (long) strdup(yytext); } ;
AddOp : '+' { $$ = (long) strdup(yytext); } ;
MultOp : '*' { $$ = (long) strdup(yytext); } ;
MultOp : '/' { $$ = (long) strdup(yytext); } ;
%%
我正在使用的测试文件是这样的:
test1 {
int amt, box;
int x, y, w;
x := 4 - 2 - 1; // 4 2 - 1 - x =
amt := 5 * y - 2; // 5 y * 2 - amt =
x := 5 * (y - 2); // 5 y 2 - * x =
box := 5 * x / amt + 3 * 4; // 5 x * amt / 3 4 * + box =
y := z; w:= 1; // z y = 1 w =
}
注释的表达式表示我应该得到的输出。因此我的语法应该返回,
1. x := 4 - 2 - 1; should produce 4 2 - 1 - x =
2. amt := 5 * y - 2; should produce 5 y * 2 - amt =
3. x := 5 * (y - 2); should produce 5 y 2 - * x =
4.box := 5 * x / amt + 3 * 4; should produce 5 x * amt / 3 4 * + box =
5. y := z; w:= 1; should produce z y = 1 w =
我的语法回来了,
1. 4 2 1 - - x =
2. I get the correct output
3. I get the correct output
4. I get the correct output
5. 5 x amt / * 3 4 * + box =
根据我的理解,我的运算符似乎没有关联。有人知道为什么会这样吗?
【问题讨论】:
-
该语法不是左递归的。左递归将是
expr: term | expr AddOp term。 -
此外,在 yacc 操作中引用
yytext几乎总是错误的。如果您想允许两种可能的语义类型,请使用语义联合。 -
除了 rici 所说的:绝对不能保证
long在 64 位平台上有 64 位(例如,sizeof(long)在 32 位和 64 位上都是 4 Windows),因此将指针存储在long中是不安全的。 -
如果你想要一个大到足以容纳指针的整数类型,你需要
intptr_t或uintptr_t。但在这种情况下,你真的想要一个%union,就像 rici 所说的那样。 -
顺便说一句,像 Yacc 中的 LALR(1) 解析器生成实际上非常适合左递归;无论递归的深度如何,左递归都以恒定的 Yacc 堆栈深度运行。这是因为生成的状态机散布了 shift 和 reduce 动作。右递归使 Yacc 解析器消化不良;部分推导堆积在 Yacc 堆栈上,然后在到达表达式末尾时进行级联归约。