Lex 词法分析实验:识别字符串
Lex 词法分析实验:识别字符串
本实验将继续改写实验 1 的程序,增加识别字符串记号的功能。字符串是以双引号括起的一串字符,需要处理转义字符和非法字符串的情况。
实验内容
- 在实验 1 的基础上,识别字符串记号
string。 - 字符串中如果出现
",则需要转义为\";如果出现\,则需要转义为\\。 - 字符串内可以包含转义字符,例如
\c,其中c可以是任意字母、数字或\、"、'中的任意一个。 - 字符串内不能包含实体的换行符。
实验步骤
- 添加识别
string的规则:
在 lex 文件中添加以下规则:
" { yylval.str = (char*)malloc(sizeof(char)*MAX_LEN); memset(yylval.str, 0, sizeof(char)*MAX_LEN); yy_push_state(IN_STRING); }
<IN_STRING>{
[^"\
]+ { strncat(yylval.str, yytext, yyleng); }
\[\"'n] { strncat(yylval.str, yytext+1, yyleng-1); }
" { yy_pop_state(); return STRING; }
{ yyerror("error: string literal contains newline"); }
. { yyerror("error: unrecognized escape sequence"); }
}
yy_push_state(IN_STRING)表示进入字符串状态。yy_pop_state()表示退出字符串状态。[^"\ ]+表示匹配除了双引号、反斜杠和换行符以外的任意字符。\[\"'n]表示匹配转义字符。"表示匹配双引号。
- 修改
main函数中的switch语句:
添加 STRING 分支:
switch (token) {
case INT: printf("INT(%d)
", yylval.i); break;
case FLOAT: printf("FLOAT(%f)
", yylval.f); break;
case ID: printf("ID(%s)
", yylval.str); break;
case STRING: printf("STRING('%s')
", yylval.str); break;
// ... 其他分支
}
- 编译运行程序,测试识别字符串功能:
例如,输入以下代码:
int main() {
int a = 123;
float b = 3.14;
char c = 'c';
char d = '\'';
char e = '\"';
char f = '\\';
char g = '\n';
char h = '\t';
char* str = "hello\nworld";
return 0;
}
预期输出结果为:
INT(123)
ID(main)
LP
RP
LC
INT(0)
ID(a)
ASSIGN
INT(123)
SEMI
FLOAT(3.140000)
ID(b)
ASSIGN
FLOAT(3.140000)
SEMI
CHAR(c)
ASSIGN
'c'
SEMI
CHAR(d)
ASSIGN
'\'
SEMI
CHAR(e)
ASSIGN
'"'
SEMI
CHAR(f)
ASSIGN
'\\'
SEMI
CHAR(g)
ASSIGN
'\n'
SEMI
CHAR(h)
ASSIGN
'\t'
SEMI
ID(str)
ASSIGN
STRING('hello\nworld')
SEMI
RETURN
INT(0)
SEMI
RC
- 测试不合法的字符串:
例如,输入以下代码:
char* str = "hello
world";
预期输出结果为:
error: string literal contains newline
STRING('')
程序应该能够正确识别并报错。
- 测试转义字符:
例如,输入以下代码:
char* str = "\"hello\\world\"";
printf("%s\n", str);
预期输出结果为:
STRING('"hello\"world"')
程序应该能够正确处理转义字符。
总结
本实验通过识别字符串记号,进一步熟悉了 lex 工具的使用,并学习了如何处理转义字符和非法字符串。这些知识在编写编译器和解释器等程序时非常有用。
原文地址: http://www.cveoy.top/t/topic/nyNx 著作权归作者所有。请勿转载和采集!