c++ - 将多种类型分配给 Bison 中的非终端

标签 c++ parsing bison yacc

我正在尝试将多种数据类型分配给非终端号码,在谷歌搜索中我发现了这个:Assigning multiple data types to a non-terminal in yacc . 但是,此语法似乎对我不起作用,因为在运行它时出现以下错误:

new11.y:53.54-55: $3 of `initialization' has no declared type
new11.y:57.81-82: $5 of `increment' has no declared type
new11.y:70.33-34: $4 of `ifelse' has no declared type

这是我的代码:

  %union{
    int ival;
    float fval;
    char *sval;
}

// define the terminal symbol token types
%token <ival> INTEGER
%token <fval> FLOAT
%token <sval> BLOCK
%token <sval> GOTO
%token PRINT IF ELSE RETURN
%token LESSTHAN LESSTHANEQUALTO GREATERTHAN GREATERTHANEQUALTO EQUALTO
%token ADD SUB MUL DIV
%token <sval> IDENTIFIER 
%type <sval> comparison

%%
//grammar which bison will parse

start:
    block statements { ; }
    | start block statements { ; }
    ;

block:
    BLOCK { cout<<"Block : "<<$1<<endl; }
    ;

number:
    INTEGER { $<ival>$=$1 }
    | FLOAT { $<fval>$=$1 }
    ;

initialization:
    IDENTIFIER EQUALTO number { cout<<$1<<" = "<<$3<<endl; }
    ;

increment:
    IDENTIFIER EQUALTO IDENTIFIER ADD number { cout <<$1<<" = "<<$3<<" + "<<$5<<endl; }
    ;

goto:
    GOTO { cout<<"GOTO : "<<$1<<endl; }
    ;

printing:
    PRINT { cout<<"printf(...)"<<endl; }
    ;

ifelse:
    IF IDENTIFIER comparison number GOTO ELSE GOTO
    { cout <<"if "<<$2<<$3<<$4<<", "<<$5<<",else, "<<$7<<endl; }
    ;

comparison:
    LESSTHAN { $$="<"; }
    | LESSTHANEQUALTO { $$="<=" }
    | GREATERTHAN { $$=">" }
    | GREATERTHANEQUALTO { $$=">=" }
    ;

statement:
    initialization
    | printing
    | goto
    | increment
    | ifelse
    | RETURN
    ;

statements:
    statements statement 
    | statement
    ;

%%

main() {
    // open a file handle to a particular file:
    FILE *myfile = fopen("test.cfg", "r");
    // make sure it is valid:
    if (!myfile) {
        cout << "I can't open a.snazzle.file!" << endl;
        return -1;
    }
    // set flex to read from it instead of defaulting to STDIN:
    yyin = myfile;
    // parse through the input until there is no more:
    do {
        yyparse();
    } while (!feof(yyin));
}

void yyerror(const char *s) {
    cout << "EEK, parse error!  Message: " << s << endl;
    // might as well halt now:
    exit(-1);
}

我哪里错了?我是不是语法不对?

最佳答案

错误信息相当清楚。您的非终端 initialization$3 of number 并且 number 需要一个 %type声明。 increment$5ifelse$4也是number,所以是同样的问题三次。

您可能需要创建一个可区分的 union 来表示整数或 float ,并在 %union 中使用该 union :

struct Number
{
    enum { INTEGER, FLOAT } type;
    union
    {
        float fval;
        int   ival;
    };
};

然后:

%union
{
    char *sval;
    Number nval;
};

此语法在 Bison 中编译 — 可能需要在 C++ 级别完成代码工作。如果匿名 union 不在 C++ 中,请在 struct Number 中为 union 添加一个名称。您的分词器需要同时设置 typestruct Numberivalfval 字段。你不能用 C++ 编写简单的 main();你必须在它前面加上 int

%{
struct Number
{
    enum { INTEGER, FLOAT } type;
    union
    {
        float fval;
        int   ival;
    };
};
%}

%union
{
    Number nval;
    char  *sval;
}

// define the terminal symbol token types
%token <nval> INTEGER
%token <nval> FLOAT
%token <sval> BLOCK
%token <sval> GOTO
%token PRINT IF ELSE RETURN
%token LESSTHAN LESSTHANEQUALTO GREATERTHAN GREATERTHANEQUALTO EQUALTO
%token ADD SUB MUL DIV
%token <sval> IDENTIFIER 
%type <sval> comparison
%type <nval> number

%%
//grammar which bison will parse

start:
    block statements { ; }
    | start block statements { ; }
    ;

block:
    BLOCK { cout<<"Block : "<<$1<<endl; }
    ;

number:
    INTEGER { $$=$1 }
    | FLOAT { $$=$1 }
    ;

initialization:
    IDENTIFIER EQUALTO number { cout<<$1<<" = "<<$3<<endl; }
    ;

increment:
    IDENTIFIER EQUALTO IDENTIFIER ADD number { cout <<$1<<" = "<<$3<<" + "<<$5<<endl; }
    ;

goto:
    GOTO { cout<<"GOTO : "<<$1<<endl; }
    ;

printing:
    PRINT { cout<<"printf(...)"<<endl; }
    ;

ifelse:
    IF IDENTIFIER comparison number GOTO ELSE GOTO
    { cout <<"if "<<$2<<$3<<$4<<", "<<$5<<",else, "<<$7<<endl; }
    ;

comparison:
    LESSTHAN { $$="<"; }
    | LESSTHANEQUALTO { $$="<=" }
    | GREATERTHAN { $$=">" }
    | GREATERTHANEQUALTO { $$=">=" }
    ;

statement:
    initialization
    | printing
    | goto
    | increment
    | ifelse
    | RETURN
    ;

statements:
    statements statement 
    | statement
    ;

%%

int main() {
    // open a file handle to a particular file:
    FILE *myfile = fopen("test.cfg", "r");
    // make sure it is valid:
    if (!myfile) {
        cout << "I can't open a.snazzle.file!" << endl;
        return -1;
    }
    // set flex to read from it instead of defaulting to STDIN:
    yyin = myfile;
    // parse through the input until there is no more:
    do {
        yyparse();
    } while (!feof(yyin));
}

void yyerror(const char *s) {
    cout << "EEK, parse error!  Message: " << s << endl;
    // might as well halt now:
    exit(-1);
}

关于c++ - 将多种类型分配给 Bison 中的非终端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22891458/

相关文章:

bison - Flex/bison 语法错误

c++ - 按照 Visual Studio 的建议,使用 fopen 而不是 fopen_s 有什么错误?

c++ - 引用抽象类的类的 copy-and-swap 习语

c# - 将6位数字解析为6个int数组

Java 从文件中解析 multipart/form-data

cmake - 无法配置 CMake 来查找 Bison 的 Homebrew 安装版本

c++ - 带有自定义删除器的 std::unique_ptr 对象的大小(带有引用捕获的 lambda)

c++ - Qt - 信息未加载到 ListView 中

bash - 使用awk从文件中读取数据

c - 如何在解析不同流的 block 时保持 Bison 状态?