c - yacc 从非终端获取零值

标签 c compiler-construction yacc

我正在按照 [编译器构造、原理和实践] 制作 C 编译器。 我几乎已经使用 yacc 制作了解析器,但是 yacc 中的一条规则出错了。

return_stmt         : RETURN SEMI { $$ = newStmtNode(ReturnK);}
                    | RETURN expression SEMI
                         { $$ = newStmtNode(ReturnK);
                           $$->child[0] = $1;
                         }

当使用“RETURN 表达式 SEMI”规则解析 return 语句时,$1 的值为零。整个来源如下 %%/* C-语法 */

program             : declaration_list
                         { savedTree = $1; } 
                    ;
declaration_list    : declaration_list declaration
                         { YYSTYPE t = $1;
                           if (t != NULL)
                             { while (t->sibling != NULL)
                                  t = t->sibling;
                               t->sibling = $2;
                               $$ = $1; }
                           else $$ = $2;
                         }
                    | declaration { $$ =$1; }
                    ;
declaration         : var_declaration { $$ = $1; }
                    | fun_declaration { $$ = $1; }
                    ;
var_declaration     : type_specifier ID SEMI
                         { $$ = newExpNode(VarK);
                           $$->type = (ExpType)$1;
                           $$->attr.name = nameStackPop();
                           $$->lineno = savedLineNo;
                         }
                    | type_specifier ID LBRACE NUM RBRACE SEMI
                         { $$ = newExpNode(VarArrayK);
                           $$->type = (ExpType)$1;
                           $$->attr.name = nameStackPop();
                           $$->lineno = savedLineNo;
                           $$->child[0] = $4;
                         }
                    ;
type_specifier      : INT { $$ = Integer; }
                    | VOID { $$ = Void; }
                    ;
fun_declaration     : type_specifier ID LPAREN params RPAREN compound_stmt
                         { $$ = newStmtNode(FunctionK);
                           $$->type = (ExpType)$1;
                           $$->attr.name = nameStackPop();
                           $$->lineno = savedLineNo;
                           $$->child[0] = $4;
                           $$->child[1] = $6;
                         }
                    ;
params              : param_list { $$ = $1; }
                    | VOID
                         { $$ = newExpNode(SingleParamK);
                           $$->type = Void;
                         }
                    ;
param_list          : param_list COMMA param
                         { YYSTYPE t = $1;
                           if (t != NULL)
                           { while (t->sibling != NULL)
                                t = t->sibling;
                             t->sibling = $3;
                             $$ = $1; }
                             else $$ = $3;
                         }
                    | param { $$ = $1; }
                    ;
param               : type_specifier ID
                         { $$ = newExpNode(SingleParamK);
                           $$->type = (ExpType)$1;
                           $$->attr.name = nameStackPop();
                         }
                    | type_specifier ID LBRACE RBRACE
                         { $$ = newExpNode(ArrayParamK);
                           $$->type = (ExpType)$1;
                           $$->attr.name = nameStackPop();
                           $$->lineno = savedLineNo;
                         }
                    ;
compound_stmt       : LCURLY local_declarations statement_list RCURLY
                         { $$ = newStmtNode(CompoundK);
                           $$->child[0] = $2;
                           $$->child[1] = $3;
                         }
                    ;
local_declarations  : local_declarations var_declaration
                         { YYSTYPE t = $1;
                           if (t != NULL)
                           { while (t->sibling != NULL)
                                t = t->sibling;
                             t->sibling = $2;
                             $$ = $1; }
                             else $$ = $2;
                         }
                    | empty { $$ = $1; }
                    ;
statement_list      : statement_list statement
                         { YYSTYPE t = $1;
                           if (t != NULL)
                           { while (t->sibling != NULL)
                                t = t->sibling;
                             t->sibling = $2;
                             $$ = $1; }
                             else $$ = $2;
                         }
                    | empty { $$ = $1; }
                    ;
statement           : expression_stmt { $$ = $1; }
                    | compound_stmt { $$ = $1; }
                    | selection_stmt { $$ = $1; }
                    | iteration_stmt { $$ = $1; }
                    | return_stmt { $$ = $1; }
                    ;
expression_stmt     : expression SEMI { $$ = $1;}
                    | SEMI { $$ = NULL; }
                    ;
selection_stmt      : IF LPAREN expression RPAREN statement
                         { $$ = newStmtNode(IfK);
                           $$->child[0] = $3;
                           $$->child[1] = $5;
                           $$->attr.withElse = FALSE;
                         }
                    | IF LPAREN expression RPAREN statement ELSE statement
                         { $$ = newStmtNode(IfK);
                           $$->child[0] = $3;
                           $$->child[1] = $5;
                           $$->child[2] = $7;
                           $$->attr.withElse = TRUE;
                         }
                    ;
iteration_stmt      : WHILE LPAREN expression RPAREN statement
                         { $$ = newStmtNode(WhileK);
                           $$->child[0] = $3;
                           $$->child[1] = $5;
                         }
                    ;
return_stmt         : RETURN SEMI { $$ = newStmtNode(ReturnK);}
                    | RETURN expression SEMI
                         { $$ = newStmtNode(ReturnK);
                           $$->child[0] = $1;
                         }
                    ;
expression          : var ASSIGN expression
                         { $$ = newExpNode(AssignK);
                           $$->type = Integer;
                           $$->child[0] = $1;
                           $$->child[1] = $3;
                         }
                    | simple_expression { $$ = $1; }
                    ;
var                 : ID
                         { $$ = newExpNode(IdK);
                           $$->type = Integer;
                           $$->attr.name = nameStackPop();
                         }
                    | ID LBRACE expression RBRACE
                         { $$ = newExpNode(IdK);
                           $$->attr.name = nameStackPop();
                           $$->child[0] = $3;
                         }
                    ;
simple_expression   : additive_expression relop additive_expression
                         { $$ = newExpNode(OpK); 
                           $$->type = Integer;
                           $$->child[0] = $1;
                           $$->child[1] = $3;
                           $$->attr.op = $2;
                         }
                    | additive_expression
                         { $$ = $1; }
                    ;
relop               : LE { $$ = LE; }
                    | LT { $$ = LT; }
                    | GT { $$ = GT; }
                    | GE { $$ = GE; }
                    | EQ { $$ = EQ; }
                    | NE { $$ = NE; }
                    ;
additive_expression : additive_expression addop term
                         { $$ = newExpNode(OpK);
                           $$->type = Integer;
                           $$->child[0] = $1;
                           $$->child[1] = $3;
                           $$->attr.op = $2;
                         }
                    | term { $$ = $1; }
                    ;
addop               : PLUS { $$ = PLUS; }
                    | MINUS { $$ = MINUS; }
                    ;
term                : term mulop factor
                         { $$ = newExpNode(OpK);
                           $$->type = Integer;
                           $$->child[0] = $1;
                           $$->child[1] = $3;
                           $$->attr.op = $2;
                         }
                    | factor { $$ = $1; }
                    ;
mulop               : TIMES { $$ = TIMES; }
                    | OVER { $$ = OVER; }
                    ;
factor              : LPAREN expression RPAREN
                         { $$ = $2; }
                    | var { $$ = $1; }
                    | call { $$ = $1; }
                    | NUM
                         { $$ = newExpNode(ConstK);
                           $$->type = Integer;
                           $$->attr.val = atoi(tokenString);
                         }
                    ;
call                : ID LPAREN args RPAREN
                         { $$ = newExpNode(CallK);
                           $$->attr.name = nameStackPop();
                           $$->child[0] = $3;
                           $$->lineno = savedLineNo;
                         }
                    ;
args                : arg_list
                         { $$ = $1; }
                    | empty
                         { $$ = $1; }
                    ;
arg_list            : arg_list COMMA expression
                         { YYSTYPE t = $1; 
                           if (t != NULL)
                           { while (t->sibling != NULL)
                                t = t->sibling;
                             t->sibling = $3;
                             $$ = $1; }
                             else $$ = $3;
                         }
                    | expression
                         { $$ = $1; }
                    ;
empty               : { $$ = NULL;}
                    ;

%%

当我使用 printf 进行调试时,我确认规则“RETURN 表达式 SEMI”中的所有其他非终结符都具有正确的值(树节点的指针)。这个 yacc 文件有什么问题?

最佳答案

$1return 标记。 $2 应该是表达式。

关于c - yacc 从非终端获取零值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26561084/

相关文章:

php - 在 C 中最快重新实现 PHP 的 htmlspecialchars 函数

.net - 跨 CPU 架构从 Windows 10 通用应用程序引用 C Dll

Python YACC EOF 立即到达

python - PLY:C 解析器中的 token 移位问题

c - GNU C 扩展 __attribute__(__cleanup__) 是如何工作的?

c - c中负数逻辑右移的实现

parsing - 将 Mathematica 移植到 Octave

compiler-errors - ANTLR4.7 : rule XXX contains a closure with at least one alternative that can match an empty string'

c++ - 无法编译 rrd

yacc - 通过宏扩展跟踪原始行号