基本说明
在PA2
中运行make lexer
,会在目录下产生一个可执行文件lexer
,运行./lexer test.cl
,即可对test.cl
中的代码进行词法分析。
.flex
文件定义了语法分析的规则,在本次PA
中,我们需要完成cool.flex
文件, 在其中设置正确的正则表达式。从而使得我们的lexer
能产生正确的词法分析结果。
具体实现
在.flex
文件中,definitions
区包含了定义全局变量、定义宏等内容;rules
区中设置各个正则表达式和对应的代码处理,每当匹配到一个正则表达式,就会执行对应的代码块;下面分别介绍definitions
区和rules
区的具体实现。
definitions区
除了已有定义,在definition区我们还做了以下定义:
- 两个全局变量,
comment_layer
保存注释的层数,用于后续处理嵌套循环,stringArray
用于存储字符串;
- 对于
cool
语言中的简单关键字也在这里做flex
定义,供后续代码中使用
具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| static int comment_layer=0; static std::vector<char> stringArray;
DARROW => CLASS class ELSE else FI fi IF if IN in INHERITS inherits LET let LOOP loop POOL pool THEN then WHILE while CASE case ESAC esac OF of NEW new ISVOID isvoid NOT not
DIGIT [0-9] TYPEID [A-Z][A-Za-z0-9_]* OBJECTID [a-z][A-Za-z0-9_]* INVALID [\[\]\ BOOL_TRUE t[Rr][Uu][Ee] BOOL_FALSE f[Aa][Ll][Ss][Ee]
|
rules区
rules
区主要对以下几类语句进行处理:
- 注释
- 关键字(固定字符)
- 单个字符
- 字符串
下面分别进行介绍。
注释处理
cool
有两种注释格式,分别是使用(*
的多行注释和使用--
的单行注释,并且支持嵌套循环,在这使用一个全局变量comment_layer
来记录嵌套数量,具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <INITIAL,COMMENTS>"(*" { ++comment_layer; BEGIN(COMMENTS);}
<COMMENTS>[^\n(*]* {}
<COMMENTS>[()*] {}
<COMMENTS>"*)" { if(comment_layer==0){ BEGIN(INITIAL); } }
<COMMENTS><<EOF>> { cool_yylval.error_msg="EOF in comment"; BEGIN(INITIAL); return (ERROR); }
<COMMENTS>\n { ++curr_lineno; }
"*)" { cool_yylval.error_msg = "Unmatched *)"; BEGIN(INITIAL); return (ERROR); }
<INITIAL>"--" { BEGIN(INLINE_COMMENTS); }
<INLINE_COMMENTS>[^\n]* {}
<INLINE_COMMENTS>\n { ++curr_lineno; BEGIN(INITIAL); }
|
固定字符、单个字符
这类字符的处理比较简单,借用一些之前的定义一一对应即可。
具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| "<-" { return ASSIGN;} "<=" { return LE; } "+" { return int('+'); } "-" { return int('-'); } "*" { return int('*'); } "/" { return int('/'); } "<" { return int('<'); } "=" { return int('='); } "." { return int('.'); } ";" { return int(';'); } "~" { return int('~'); } "{" { return int('{'); } "}" { return int('}'); } "(" { return int('('); } ")" { return int(')'); } ":" { return int(':'); } "@" { return int('@'); } "," { return int(','); }
{DARROW} { return DARROW; } {CLASS} { return (CLASS); } {ELSE} { return (ELSE); } {FI} { return (FI); } {IF} { return (IF); } {IN} { return (IN); } {INHERITS} { return (INHERITS); } {LET} { return (LET); } {LOOP} { return (LOOP); } {POOL} { return (POOL); } {THEN} { return (THEN); } {WHILE} { return (WHILE); } {CASE} { return (CASE); } {ESAC} { return (ESAC); } {OF} { return (OF); } {NEW} { return (NEW); } {ISVOID} { return (ISVOID); } {NOT} { return (NOT); }
{TYPEID} { cool_yylval.symbol=idtable.add_string(yytext); return TYPEID; }
{OBJECTID} { cool_yylval.symbol=idtable.add_string(yytext); return OBJECTID; }
[ \f\r\t\v]+ { }
{DIGIT}+ { cool_yylval.symbol=inttable.add_string(yytext); return INT_CONST; }
{INVALID} { cool_yylval.error_msg=yytext; return ERROR; }
{BOOL_TRUE} { cool_yylval.boolean=true; return BOOL_CONST; }
{BOOL_FALSE} { cool_yylval.boolean=false; return BOOL_CONST; }
|
字符串处理
字符串处理主要需要注意的是转义字符和一些不合法状态的处理,具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| "\n" { curr_lineno++; }
<INITIAL>\" { stringArray.clear(); BEGIN(STRING); }
<STRING>[^\\\"\n]* { stringArray.insert(stringArray.end(),yytext,yytext+yyleng); }
<STRING>\\ { BEGIN(STRING_TEMP); }
<STRING>\\\n { stringArray.push_back('\n'); ++curr_lineno; }
<STRING_TEMP>n { stringArray.push_back('\n'); BEGIN(STRING); }
<STRING_TEMP>b { stringArray.push_back('\b'); BEGIN(STRING); }
<STRING_TEMP>t { stringArray.push_back('\t'); BEGIN(STRING); }
<STRING_TEMP>f { stringArray.push_back('\f'); BEGIN(STRING); }
<STRING_TEMP>[^nbtf0] { stringArray.push_back(yytext[0]); BEGIN(STRING); }
<STRING_TEMP>0 { cool_yylval.error_msg="String contains null character."; BEGIN(INITIAL); return(ERROR); }
<STRING>\n { cool_yylval.error_msg="Unterminated string constant."; ++curr_lineno; BEGIN(INITIAL); return(ERROR); }
<STRING>\" { stringArray.insert(stringArray.end(),yytext,yytext+yyleng-1); if(stringArray.size()>1024){ yylval.error_msg="String constant too long."; BEGIN(INITIAL); return (ERROR); } cool_yylval.symbol=stringtable.add_string(&stringArray[0],stringArray.size()); BEGIN(INITIAL); return(STR_CONST); }
<STRING,STRING_TEMP><<EOF>> { cool_yylval.error_msg="EOF in string constant"; BEGIN(INITIAL); return(ERROR); }
|
结果测试
运行make dotest
,编译lexer
并将当前目录下cool
文件test.cl
传递给这个lexer
,得到测试的输出。为了判断结果是否正确,我们需要把我们的cool.flex
结果和标准lexer
的输出结果进行比较,通过checker
工具检查,可以发现结果是一致的。
除了test.cl
中的例子,还需要对其他情况进行测试,这部分写在test1.cl
中,如下,测试了没有“
、字符串中包含\0
、字符串长度超出限制(cool.flex
中将长度限制为1024位)、EOF
等情况,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| (* my test *) *) class Main inherits IO { myString1 : String; myString2: String; myString3: String;
main() : SELF_TYPE { myString1<-"fsgd myString2<-"dfad \0 dfad"; myString3<-"vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitojvdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitojvdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitojvdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitojvdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitojvdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitojvdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitojvdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitojvdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitojvdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitojvdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitojvdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitojvdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitojvdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitojvdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitojvdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj vdskhv jsdslkhlb elfjldasjv aljaljdvlk lkdvjsldkvjsad dlkhfaj reitoj"; } myString1<-"123\0" myString2<-"123\\0" myString3 }; ""
|