用到flex和bison,總是會出現一些奇怪的問題,然后網上又查不到直接的解決辦法。現在來總結一下遇到的和解決的問題。
1. bison的C++接口
2. flex的C++接口
3. location的使用
先說簡單一點的,location的使用,
在Bison手冊里給出的Calculator的例子里面,使用stdin作為輸入,在lex文件里定義了
# define YY_USER_ACTION yylloc->columns (yyleng);
在輸出位置信息的時候,行數始終是1,這個對於文件作為輸入就需要做些修改了。在
http://oreilly.com/linux/excerpts/9780596155971/error-reporting-recovery.html
里面提到了解決辦法,換一種YY_USER_ACTION的定義,
/* handle locations */ int yycolumn = 1; #define YY_USER_ACTION yylloc.first_line = yyloc.last_line = yylineno; \ yylloc.first_column = yycolumn; yylloc.last_column = yycolumn+yyleng-1; \ yycolumn += yyleng;
但是這樣定義之后,會提示yylloc不能使用.作成員運算符,沒有first_line, last_line等成員,yylineno沒有定義。
yylloc在flex和bison里面都會用到,yylex函數的定義,
#define YY_DECL int \ yylex(yy::CktParser::semantic_type* yylval, \ yy::CktParser::location_type* yylloc) YY_DECL;
在這里可以看到,yylex的參數是yylloc指針,所以上面的.運算符應該改為->。或者把YY_DECL的函數參數改為location_type& yylloc.
但是還是出現yylloc沒有first_line的錯誤,在網上和Bison的手冊里,可以查到YYLTYPE類型,
typedef struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; } YYLTYPE;
在flex和bison里面,還有一個和這個類型相似的定義,YYSTYPE,並且在bison生成的頭文件里,可以看到
typedef YYSTYPE semantic_type;
但卻找不到typedef YYLTYPE location_type; 而是
typedef location location_type;但location的數據成員只有begin和end。並且在所有生成的文件里,找不到YYLTYPE。
這樣問題似乎就很奇怪了。
當看到Position的定義時,問題就不再是問題了。Position有兩個數據成員,line和column。
所以YY_USER_ACTION定義為,
#define YY_USER_ACTION yylloc->begin.line = yylloc->end.line = yylineno-1; \ yylloc->begin.column = yycolumn; yylloc->end.column = yycolumn+yyleng-1; \ yycolumn += yyleng;
還有就是lineno的聲明,在前面加上
%option yylineno
問題到這,似乎就應該完全解決了,但是,當做一個簡單的測試的時候,卻發現位置信息還是不對,行數會多一行,列數好像還在累加,
看來yylineno的初值應該有些問題,yycolumn的累加有些問題。
做如下的修改,
yylloc.first_line = yyloc.last_line = yylineno - 1; // 減去初始值 [\n] { yycolumn = 1; } // 重置為1
直到現在,位置信息才基本正確了。
另外兩部分,有空再整理吧。
Flex & Bison 更多的參考:
1. http://ryan1987.blogbus.com/tag/lex/ Flex和Bison的C++解決方案 一個系列
2. http://panthema.net/2007/flex-bison-cpp-example/ 一個很好的例子
3. http://www.lrde.epita.fr/~akim/ccmp/doc/gnuprog2/index.html#Top 除了flex & bison, 還有其他很有用的軟件的介紹,包括libstdc++和make。