[英]Problem with my parser.y (FLEX/BISON). How to declare '$4'?
[英]How to use flex with my own parser?
我想將詞法分析留給詞法分析,但自己開發解析器。
我制作了一個token.h標頭,其中包含令牌類型的枚舉和簡單的類層次結構,
對於lex規則:
[0-9]+ {yylval = new NumToken(std::stoi(yytext));return NUM;}
如何從解析器代碼中獲取NumToken指針? 假設我只想打印出令牌。
while(true)
{
auto t = yylex();
//std::cout <<yylval.data<<std::endl; // What goes here ?
}
我可以使用yacc / bison進行此操作,但是找不到有關如何手動執行此操作的任何文檔或示例。
在傳統的bison / flex解析器中, yylval
是在bison生成的解析器中定義的全局變量,並在bison生成的頭文件中聲明(應在包含在生成的掃描器中#include)。 因此,一個簡單的解決方案就是復制它:在token.h
聲明yylval
(作為全局token.h
並在解析器中的某個位置定義它。
但是現代編程風格已經從使用全局變量轉變了(有充分的理由),實際上,如果需要,甚至flex
也會生成不依賴於全局狀態的掃描程序。 要請求這樣的掃描儀,請指定
%option reentrant
在您的掃描儀定義中。 默認情況下,這會將yylex
的原型更改為:
int yylex(yyscan_t yyscanner);
其中yyscan_t
是不透明的指針。 (這是C,所以意味着它是一個void*
。)您可以在Flex手冊中閱讀有關細節; 最重要的要點是,您可以要求flex還生成一個頭文件(帶有%option header-file
),以便其他翻譯單元可以引用各種函數來創建,銷毀和操作yyscan_t
,並且您需要最少創建一個,以便yylex
在某處存儲其狀態。 (理想情況下,您也將其銷毀。)[注1]。
使用掃描儀折返從預期的方式bison
是啟用%option bison-bridge
(和%option bison-location
,如果你的詞法分析器每個令牌生成源位置信息)。 這將為yylex
原型添加一個附加參數:
int yylex(YYSTYPE *yylval_param, yyscan_t scanner);
使用`%option bison-locations',添加了兩個參數:
int yylex(YYSTYPE *yylval_param,
YYLTYPE *yylloc_param,
yyscan_t scanner);
flex生成的代碼未聲明語義類型YYSTYPE
和位置類型YYLTYPE
。 它們必須出現在您#include到掃描儀中的token.h
標頭中。
野牛橋參數的目的是提供一種將語義值yylval
返回給調用方(即解析器)的機制。 由於yylval
實際上與參數yylval_param
[注2]相同,因此它將是指向實際語義值的指針 ,因此您需要在flex動作中編寫(例如) yylval->data = ...
所以這是做到這一點的一種方法。
替代bison-bridge
一種可能更簡單的選擇是僅提供您自己的yylex
原型,您可以使用宏YY_DECL
。 例如,您可以執行以下操作(如果YYSTYPE很簡單):
#define YY_DECL std::pair<int, YYSTYPE> yylex(yyscan_t yyscanner)
然后一條規則可以返回該對:
[0-9]+ {return std::make_pair(NUM, new NumToken(std::stoi(yytext));}
顯然,此主題有很多變體。
不幸的是,生成的標頭包含很多不必要的包,,包括一堆用於標准“全局變量”的宏定義,這些宏定義將不起作用,因為在可重入的掃描器中,這些變量只能在flex動作中使用。
用bison-bridge
生成的掃描器將yylval
定義為一個宏,該宏引用不透明狀態結構中的一個字段,並將yylval_param
存儲到該字段中。 yyget_lval
和yyset_lval
函數是為了從yylex
外部獲取或設置此字段。 我不知道為什么; 似乎介於不必要和危險之間,因為狀態將包含指向 yylex
調用中提供的值的指針,一旦調用返回,它很可能是懸空的指針。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.