为野牛中的非终端分配多种类型

Assigning multiple types to non-terminals in bison

本文关键字:分配 种类 类型 终端      更新时间:2023-10-16

我正在尝试为非终端号码分配多种数据类型,并在谷歌搜索时发现:在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);
}

我哪里出错了?我没有正确使用语法吗?

错误消息相当清晰。您的非终initializationnumber $3number需要%type声明。 increment$5ifelse$4也是number,所以是同一个问题三次。

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

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

然后:

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

此语法在 Bison 中编译 — 在C++级别可能有代码工作要做。 如果匿名联合不在C++中,请在 struct Number 中添加联合的名称。 您的分词器需要同时设置typeivalfval字段struct Number。 你不能用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);
}