c++ - 使用 Bison 解析简单 C 源代码的问题

标签 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 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);
        $$ = &params;
        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);
}
然后我尝试使用它来解析以下源代码
void empty(int a) { }
但我得到以下输出
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 , 什么时候应该是 empty .我已将错误范围缩小到特定位置:parameter_list非终端被正确解析,但是当它被移动到 parameter_type_list ,它变成了一个完全不同的对象。您可以从运行时打印的信息中看到这一点。
显然我做错了什么,但我无法弄清楚。任何帮助,将不胜感激。

最佳答案

该声明(和其他类似声明)是明确的未定义行为:

$$ = &decl;
您正在尝试存储指向其生命周期即将结束的局部变量的指针。当最终使用该悬空指针的值时,它不再引用任何内容。
我强烈建议您添加-Wall到你的 g++ 标志。我不知道 gcc 是否会检测到这个错误,尤其是在没有优化标志的情况下,但不给它机会警告你是没有意义的。
如果没有看到您的弹性代码,我无法判断您是否也将悬空指针作为标记的语义值传递,这是神秘地改变语义值的另一个常见原因。您可能也想检查一下。

关于c++ - 使用 Bison 解析简单 C 源代码的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64951382/

相关文章:

c++ - 如何解决 YACC 中的 Shift/Reduce 冲突

java - 在 array-android 应用程序中传递数组列表

c++ - 从模板参数中提取 simd vector 长度以用于本地类型

c++ - 语义 Action 提升

c - 求 500 的阶乘并将其存储在变量中...并执行计算...如何存储这么大的数字?

c - 如何在Linux上的多线程下获取用户堆栈的底部

c++ - 如何编译Detours Express 3.0?

c++ - 类到模板错误 : invalid use of non-static data member

c++ - posix_fallocate 是否适用于以追加模式打开的文件?

用于查找 R 中以空格分隔的两个或多个单词名称的正则表达式