[英]Token with several types in Bison
我想用 Bison 編寫一個解析器,我正在嘗試解析一個文件,其中參數的值為 integer 或字符串。 換句話說,我想要一個有兩種類型的令牌。 例如,假設我有以下格式:
<id>:<value>
<value>
可以是 integer 或字符串。
注意:在 Bison 中,在“.y”文件中,我定義類型如下
%union{
unsigned number;
char* string;
}
%token value
%type<"type of value, it can be an integer or a string. The problem is here, what should I define"> value
問:如何實現解析器,其中一個令牌有多種類型?
最常見的是,您不會在詞法分析器中作為標記執行此操作,而是在解析器中作為非終端執行此操作。 因此,您的詞法分析器將識別兩個獨立的標記INT
和STRING
,並且您的解析器將接受其中任何一個作為value
並執行適當的操作。 所以你最終可能會得到類似的東西:
%union {
unsigned number;
char *string;
struct Node *node;
}
%token<number> INT
%token<string> STRING
%type<node> value
:
value : INT { $$ = createValueNodeFromInt($1); }
| STRING { $$ = createValueNodeFromString($2); }
與您在實現語言中執行此操作的方式相同,因為 bison 只是一個預處理器。
如果實現語言是C,那么它基本上歸結為一個可區分的聯合(qv); 也就是說,一個包含enum
和union
的struct
,其中enum
(通常稱為“標簽”)指示union
的哪些成員處於活動狀態。 請注意,bison 的並集沒有區別,不幸的是,bison 沒有提供自動設置標簽的語法,所以最好的辦法是定義 getter 和 setter 函數。
在 C++ 中,您可以使用std::variant
(如果您的 C++ 版本不夠新,則可以使用boost::variant
),只要您使用 C++ 代碼生成器。 (The C stack cannot contain non-trivial C++ types.) Bison's C++ generator can provide a variant class, but like the C union, it's not discriminated and so cannot help you in this application. ( std::variant
和其他非平凡的 C++ 類型的性能通過使用移動語義大大增強。最近的野牛版本確實提供了一種自動插入std::move
的機制,這可以幫助很多。但是一定要小心需要避免使用無效值。有關詳細信息,請參閱野牛手冊。)
在 AST 的 C 實現中使用可區分聯合是很常見的,在這種情況下,使用相同的數據類型在掃描器和解析器之間進行通信是很自然的。 但這會在兩個組件之間產生額外的依賴關系。 此外,相同的詞法模式與兩種不同數據類型的對象匹配是非常罕見的,因此變體類型對掃描器沒有多大用處,正如@ChrisDodd 在另一個答案中所說的那樣。 因此,您經常會發現使用變體類型的解析器最終會將標記包裝在單元產生式中,以便將值引入內部類型。
對某些語義類型使用可區分的聯合往往會感染整個項目。 因此,如果您從這條路開始,請准備好自始至終使用它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.