Назначение нескольких типов нетерминалам в зубре

0

Я пытаюсь назначить несколько типов данных для номера, отличного от терминала, и при поиске в googling. Я нашел это: Назначение нескольких типов данных для нетерминала в 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);
}

Где я здесь не так? Я не использовал синтаксис правильно?

Теги:
parsing
bison
yacc

1 ответ

1
Лучший ответ

Сообщение об ошибке достаточно ясно. Для вашей нетерминальной initialization $3 number и number требуется объявление %type. $5 от increment и $4 от ifelse также number, так что это ifelse и та же проблема три раза.

Вероятно, вам нужно создать дискриминированный союз, чтобы представлять либо целое число, либо float, и использовать этот союз в %union:

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

а потом:

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

Эта грамматика компилируется в Bison - вероятно, работа над кодом на уровне C++. Если анонимные объединения не находятся в C++, добавьте имя для объединения внутри struct Number. Ваш токенизатор должен будет указать как type и ival или fval в struct Number. Вы не можете написать обычный main() в C++; вы должны префикс его с помощью 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);
}
  • 0
    Я попробовал, но у меня это не работает. Мне интересно, как можно распечатать нетерминальный номер с типом Number с шагом 5 долларов? Также сделайте это INTEGER {$$ = $ 1} | FLOAT {$$ = $ 1} need ";" ?
  • 0
    Для Bison пропущенные точки с запятой не имеют значения - для компилятора C ++ они, вероятно, имеют значение (поэтому добавьте их). Ваш комментарий "это не работает для меня" не подлежит обсуждению; это работает (или работал) для меня. Вам нужно будет задать новый вопрос в MCVE ( Как создать минимальный, полный и проверяемый пример? ), И если я его увижу или вы добавите здесь комментарий, я могу его посмотреть. Что касается распечатки, вам понадобится условный код: cout << $1 << " = " << $3 << " + "; if ($5.type == INTEGER) cout << $5.ival; else cout << $5.fval; cout << endl; или около того.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню