1. 偷吃步 簡易法
在.l檔直接include c++ std library,用flex產生lex.yy.c後,再用g++去compile即可。
2. c++達人 完全物件法
flex提供了一個Lex的c++版,.l檔的寫法完全class物件化,因此用了這種方法,並不能與之前的寫法相容喔。
使用方法有兩種:
a. 在.l檔裡,檔案開頭加上%option c++
b. flex指令加上-+
而flex compile過後的檔案是lex.yy.cc,而非lex.yy.c。而且會幫你自動include FlexLexer.h檔。檔案裡頭宣告了兩個class:FlexLexer和yyFlexLexer,FlexLexer是一個interface,是給yyFlexLexer繼承的,原本用到的lex c function,全部都被包進class yyFlexLexer裡,所以,在使用時,必須先宣告一個yyFlexLexer物件來使用,原本c的yyin不見了,所以要指定input、output的來源必須透過yyFlexLexer的constructor來指定(預設是stdin & stdout),下面會給個範例可以讀檔當input。
將c++版的class yyFlexLexer裡面的function與原本的c版的lex做簡單的比較:
const char * YYText()
回傳目前match的token字串,與c版的yytext相同。
int YYLeng()
回傳目前match的token字串長度,與c版的yyleng相同。
int lineno() const
回傳目前parser到的是文件中的第幾行(若要使用,記得寫入%option yylineno)
以下有個簡單完整的例子,是用c++版的Flex寫的,可以parser出文件中的number, name, string:
%option noyywrap
%{
using std::cout;
int mylineno = 0;
%}
string \"[^\n"]+\"
ws [ \t]+
alpha [A-Za-z]
dig [0-9]
name ({alpha}|{dig}|\$)({alpha}|{dig}|[_.\-/$])*
num1 [-+]?{dig}+\.?([eE][-+]?{dig}+)?
num2 [-+]?{dig}*\.{dig}+([eE][-+]?{dig}+)?
number {num1}|{num2}
%%
{ws} ;/* skip blanks and tabs */
{number} cout << "number " << YYText() << '\n';
\n mylineno++;
{name} cout << "name " << YYText() << '\n';
{string} cout << "string " << YYText() << '\n';
%%
#include <fstream>
int main( int argc, char **argv )
{
std::ifstream input;
FlexLexer* lexer;
++argv, --argc;
//--- File input ---//
if ( argc > 0 ){
input.open(argv[0]);
lexer = new yyFlexLexer( &input, &std::cout );
}
//--- Stdin ---//
else{
lexer = new yyFlexLexer;
}
while( lexer->yylex() != 0 );
return 0;
}
compile的指令:
flex -+ xxx.l
g++ lex.yy.cc -o myoutput
參考文章:FreeBSD flex
沒有留言:
張貼留言