我是flex / bison的新手,并尝试实现我的解析器/词法分析器的第一步......
在我的“tokens.l”文件中,我执行以下操作来识别“关键字”:
"surface" return (yylval.token=TSURFACESHADER);
在我的parser.y文件中,我执行以下操作来声明TSURFACESHADER:
%token <int> TSURFACESHADER
但是当我编译时出现以下错误:
error C2065: 'TSURFACESHADER' : undeclared identifier
你对这个问题有什么看法吗?此外,我在生成解析器时遇到了一些错误,在使用它时,它无法“发现”使用“surface”关键字描述的“着色器”!它告诉我,我的着色器是一个功能!
例如,这是一个要解析的小代码(着色器):
surface matte(float Kd, float Cs) { int x = Kd * 5 + 3 }
感谢您的帮助
我也加入了我的.l和.y文件
tokens.l文件
/* Option 'noyywrap' indicates that when EOF is hit, yyin does not automatically reset to another file. */
%option noyywrap
%{
#include <string>
#include "node.h"
#include "parser.hpp"
#define SAVE_TOKEN yylval.string = new std::string(yytext, yyleng)
#define TOKEN(t) (yylval.token = t)
#define YY_NEVER_INTERACTIVE 1
//extern "C" int yywrap() { }
%}
%%
[ \t\n] ;
"surface" return (yylval.token=TSURFACESHADER);
[a-zA-Z_][a-zA-Z0-9_]* SAVE_TOKEN; return TIDENTIFIER;
[0-9]+\.[0-9]* SAVE_TOKEN; return TDOUBLE;
[0-9]+ SAVE_TOKEN; return TINTEGER;
"=" return TOKEN(TEQUAL);
"==" return TOKEN(TCEQ);
"!=" return TOKEN(TCNE);
"<" return TOKEN(TCLT);
"<=" return TOKEN(TCLE);
">" return TOKEN(TCGT);
">=" return TOKEN(TCGE);
"(" return TOKEN(TLPAREN);
")" return TOKEN(TRPAREN);
"{" return TOKEN(TLBRACE);
"}" return TOKEN(TRBRACE);
"." return TOKEN(TDOT);
"," return TOKEN(TCOMMA);
"+" return TOKEN(TPLUS);
"-" return TOKEN(TMINUS);
"*" return TOKEN(TMUL);
"/" return TOKEN(TDIV);
. printf("Unknown token!\n"); yyterminate();
%%
和parser.y文件
%{
#include "node.h"
NBlock *programBlock; /* the top level root node of our final AST */
extern int yylex();
void yyerror(const char *s) { printf("ERROR: %s\n", s); }
%}
/* Represents the many different ways we can access our data */
%union {
Node *node;
NBlock *block;
NExpression *expr;
NStatement *stmt;
NIdentifier *ident;
NVariableDeclaration *var_decl;
std::vector<NVariableDeclaration*> *varvec;
std::vector<NExpression*> *exprvec;
std::string *string;
int token;
}
/* Define our terminal symbols (tokens). This should match our tokens.l lex file. We also define the node type they represent. */
%token <string> TIDENTIFIER TINTEGER TDOUBLE
%token <token> TCEQ TCNE TCLT TCLE TCGT TCGE TEQUAL
%token <token> TLPAREN TRPAREN TLBRACE TRBRACE TCOMMA TDOT
%token <token> TPLUS TMINUS TMUL TDIV
%token <int> TSURFACESHADER
/* Define the type of node our nonterminal symbols represent.
The types refer to the %union declaration above. Ex: when
we call an ident (defined by union type ident) we are really
calling an (NIdentifier*). It makes the compiler happy.
*/
%type <ident> ident
/* %type <ident> shadertype */
%type <expr> numeric expr
%type <varvec> func_decl_args
%type <varvec> shader_decl_args
%type <exprvec> call_args
%type <block> program stmts block
%type <stmt> stmt var_decl func_decl shader_decl
%type <token> comparison
/* Operator precedence for mathematical operators */
%left TPLUS TMINUS
%left TMUL TDIV
%start program
%%
program : stmts { programBlock = $1; }
;
stmts : stmt { $$ = new NBlock(); $$->statements.push_back($<stmt>1); }
| stmts stmt { $1->statements.push_back($<stmt>2); }
;
stmt : var_decl | func_decl | shader_decl
| expr { $$ = new NExpressionStatement(*$1); }
;
block : TLBRACE stmts TRBRACE { $$ = $2; }
| TLBRACE TRBRACE { $$ = new NBlock(); }
;
var_decl : ident ident { $$ = new NVariableDeclaration(*$1, *$2); }
| ident ident TEQUAL expr { $$ = new NVariableDeclaration(*$1, *$2, $4); }
;
shader_decl : TSURFACESHADER ident TLPAREN shader_decl_args TRPAREN block
{ $$ = new NShaderDeclaration(*$2, *$4, *$6); delete $4; }
;
shader_decl_args : /*blank*/ { $$ = new VariableList(); }
| var_decl { $$ = new VariableList(); $$->push_back($<var_decl>1); }
| shader_decl_args TCOMMA var_decl { $1->push_back($<var_decl>3); }
;
func_decl : ident ident TLPAREN func_decl_args TRPAREN block
{ $$ = new NFunctionDeclaration(*$1, *$2, *$4, *$6); delete $4; }
;
func_decl_args : /*blank*/ { $$ = new VariableList(); }
| var_decl { $$ = new VariableList(); $$->push_back($<var_decl>1); }
| func_decl_args TCOMMA var_decl { $1->push_back($<var_decl>3); }
;
ident : TIDENTIFIER { $$ = new NIdentifier(*$1); delete $1; }
;
numeric : TINTEGER { $$ = new NInteger(atol($1->c_str())); delete $1; }
| TDOUBLE { $$ = new NDouble(atof($1->c_str())); delete $1; }
;
expr : ident TEQUAL expr { $$ = new NAssignment(*$<ident>1, *$3); }
| ident TLPAREN call_args TRPAREN { $$ = new NMethodCall(*$1, *$3); delete $3; }
| ident { $<ident>$ = $1; }
| numeric
| expr comparison expr { $$ = new NBinaryOperator(*$1, $2, *$3); }
| TLPAREN expr TRPAREN { $$ = $2; }
;
call_args : /*blank*/ { $$ = new ExpressionList(); }
| expr { $$ = new ExpressionList(); $$->push_back($1); }
| call_args TCOMMA expr { $1->push_back($3); }
;
comparison : TCEQ | TCNE | TCLT | TCLE | TCGT | TCGE
| TPLUS | TMINUS | TMUL | TDIV
;
%%
答案 0 :(得分:2)
您需要在tokens.l文件中包含行#include "parser.tab.h"
,以便在使用bison -d parser.y
你有一个#include "parser.hpp"
行,但是不清楚parser.hpp是什么或它来自哪里 - 你可能试图将parser.tab.h重命名为parser.hpp而这在某种程度上是错误的