C++ 使用Bison解析简单C源代码时出现的问题
下面是我正在使用的解析器代码C++ 使用Bison解析简单C源代码时出现的问题,c++,c,parsing,grammar,bison,C++,C,Parsing,Grammar,Bison,下面是我正在使用的解析器代码 %{ #include <cstdio> #include <iostream> #include <cstring> #include <stdio.h> #include "c.ast.hpp" #include <typeinfo> #define YYDEBUG 1 using namespace std; // stuff from flex that bison need
%{
#include <cstdio>
#include <iostream>
#include <cstring>
#include <stdio.h>
#include "c.ast.hpp"
#include <typeinfo>
#define YYDEBUG 1
using namespace std;
// stuff from flex that bison needs to know about:
extern "C" int yylex();
int yyparse(BlockOfFunctions *ast);
extern "C" FILE *yyin;
void yyerror(BlockOfFunctions *ast, const char *s);
#define TRACE printf("reduce at line %d\n", __LINE__);
%}
%token IDENTIFIER I_CONSTANT F_CONSTANT STRING_LITERAL FUNC_NAME SIZEOF
%token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP
%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN
%token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN
%token XOR_ASSIGN OR_ASSIGN
%token TYPEDEF_NAME ENUMERATION_CONSTANT
%token TYPEDEF EXTERN STATIC AUTO REGISTER INLINE
%token CONST RESTRICT VOLATILE
%token BOOL CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE VOID
%token COMPLEX IMAGINARY
%token STRUCT UNION ENUM ELLIPSIS
%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN
%token ALIGNAS ALIGNOF ATOMIC GENERIC NORETURN STATIC_ASSERT THREAD_LOCAL
%start translation_unit
%parse-param {BlockOfFunctions *ast}
%union {
string *str;
TypeSpecifier typespec;
FunctionDefinition *func;
BlockOfFunctions *blockfunc;
Declaration *decl;
vector<Declaration> *decls;
Signature *sig;
}
%type<typespec> type_specifier declaration_specifiers
%type<str> IDENTIFIER
%type<func> external_declaration function_definition
%type<blockfunc> translation_unit
%type<decl> parameter_declaration
%type<decls> parameter_list parameter_type_list
%type<sig> declarator direct_declarator
%%
declaration_specifiers
: type_specifier { TRACE $$ = $1; }
;
type_specifier
: VOID {
cout << "creating void" << endl;
$$ = TypeSpecifier::Void; }
| INT { cout << "creating int" << endl; $$ = TypeSpecifier::Int; }
;
declarator
: direct_declarator { $$ = $1; }
;
direct_declarator
: IDENTIFIER {
Signature sig;
string name = *$1;
sig.name = name;
$$ = &sig;
cout << "creating identifier " << sig.name << endl;
}
| direct_declarator '(' parameter_type_list ')' {
cout << "with argument" << endl;
cout << "got declarator " << *$1 << endl;
cout << "creating declaration " << $3->at(0) << endl;
$$ = $1;
}
| direct_declarator '(' ')' {
$$ = $1;
cout << "argument less function" << endl;
}
;
parameter_type_list
: parameter_list {
$$ = $1;
cout << "creating parameter type list " << $$->at(0) << endl;
}
;
parameter_list
: parameter_declaration {
vector<Declaration> params;
cout << "pushing back " << *$1 << endl;
params.push_back(*$1);
$$ = ¶ms;
cout << "creating parameter declaration " << $$->at(0) << endl;
}
;
parameter_declaration
: declaration_specifiers declarator {
cout << "creating param declaration" << endl;
Declaration decl;
string name = $2->name;
decl.type = $1;
decl.name = name;
$$ = &decl;
}
;
translation_unit
: external_declaration { ast->block.push_back(*$1); }
| translation_unit external_declaration { ast->block.push_back(*$2); }
;
external_declaration
: function_definition { TRACE $$ = $1; }
;
function_definition
: declaration_specifiers declarator '{' '}' {
string name = $2->name;
FunctionDefinition fn;
fn.ret = $1;
fn.name = name;
$$ = &fn;
}
;
%%
#include <stdio.h>
void yyerror(BlockOfFunctions *ast, const char *s)
{
fflush(stdout);
fprintf(stderr, "*** %s\n", s);
}
但我得到以下输出
bison -t -v -o c.tab.cpp -d c.y
flex -o c.lex.cpp -l c.l
g++ c.tab.cpp c.lex.cpp cc.cpp -lm -ll -lfl -o cc
./cc examples/test.c
creating void
reduce at line 63
creating identifier empty
creating int
reduce at line 63
creating identifier a
creating param declaration
pushing back declaration: int a
creating parameter declaration declaration: int a
creating parameter type list declaration: void
with argument
got declarator signature: a
creating declaration declaration: void
reduce at line 129
retv = 0
function: void a
它错误地将函数名解析为a
,而函数名应该是空的
。我已经将错误缩小到一个特定的位置:正确地解析了参数类型列表
非终端,但当它上移到参数类型列表
时,它会变成一个完全不同的对象。您可以从运行时打印的信息中看到这一点
很明显我做错了什么,但我不明白。任何帮助都将不胜感激。此声明(以及其他类似声明)是明确的未定义行为:
$$ = &decl;
您正试图存储指向生存期即将结束的局部变量的指针。当这个悬空指针的值最终被使用时,它不再引用任何东西
我强烈建议您在g++标志中添加-Wall
。我不知道gcc是否会检测到这个错误,特别是在没有优化标志的情况下,但没有机会警告您是没有意义的
在没有看到flex代码的情况下,我无法判断您是否也在传递悬空指针作为标记的语义值,这是导致语义值神秘变化的另一个常见原因。你也可以检查一下。这很有趣,我没想到。我对C++没有经验,你能告诉我做这个的正确方法吗?我的意思是在这种特殊情况下返回指向对象的指针。我必须以这样或那样的方式返回指向对象的指针,但据我所知,我做得不对。我使用了
new
操作符,并在以后不再使用对象时使用delete
d。修复了一切,非常感谢!
$$ = &decl;