Я пытаюсь назначить несколько типов данных для номера, отличного от терминала, и при поиске в 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);
}
Где я здесь не так? Я не использовал синтаксис правильно?
Сообщение об ошибке достаточно ясно. Для вашей нетерминальной 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);
}
cout << $1 << " = " << $3 << " + "; if ($5.type == INTEGER) cout << $5.ival; else cout << $5.fval; cout << endl;
или около того.