如何输出yytext的一部分值?
How to output a portion of the value of yytext?
我创建了一个词法分析器来标记 XML 文档。我在这条消息的底部显示词法分析器。
对于此 XML 文档:
<?xml version="1.0" encoding="UTF-8"?>
<Document version="1.0">
<message>Hello, world</message>
</Document>
词法分析器产生这个输出:
Start Tag = <Document
Attribute Name = version
Attribute Value = 1.0
Start Tag = <message
Element Value = Hello, world
End Tag = </message>
End Tag = </Document>
但是,我不希望输出是:
Start Tag = <Document
相反,我希望输出为:
Start Tag = Document
即没有<
符号。
为了实施该更改,在我的词法分析器的 main() 例程中,我更改了以下内容:
printf("Start Tag = %s\n", yytext);
对此:
printf("Start Tag = %s\n", yytext[1]);
我一做出更改,词法分析器就停止输出任何内容(即,在我做出更改后输出为空)。为什么那个微小的变化会导致没有输出?除了第一个字符之外,yytext 的值的正确输出方式是什么?
这是我的词法分析器:
%x ELEMENT_CONTENT
%x ATTRIBUTE
%x QUOTED_ATTRIBUTE_VALUE
%x APOSTROPHED_ATTRIBUTE_VALUE
%{
enum yytokentype {
START_TAG = 258,
END_TAG = 259,
ELEMENT_VALUE = 260,
ATTRIBUTE_NAME = 261,
ATTRIBUTE_VALUE = 262,
JUNK = 263
};
int yyval;
%}
%%
<INITIAL>{
"<?xml"[^?>]+"?>"[[:space:]]+ {}
">" {}
"<"[^/>[:space:]]+ { BEGIN ATTRIBUTE; return(START_TAG); }
"</"[^[:space:]]+ { return(END_TAG); }
[[:space:]]+ {}
}
<ATTRIBUTE>{
">" { BEGIN ELEMENT_CONTENT; }
"/>" { BEGIN INITIAL; }
[[:space:]]+ {}
[^[:space:]="'>/]+ { return(ATTRIBUTE_NAME); }
"=" {}
\" { BEGIN QUOTED_ATTRIBUTE_VALUE; }
"'" { BEGIN APOSTROPHED_ATTRIBUTE_VALUE; }
}
<QUOTED_ATTRIBUTE_VALUE>{
[^"]+ { return(ATTRIBUTE_VALUE); }
\" { BEGIN ATTRIBUTE; }
}
<APOSTROPHED_ATTRIBUTE_VALUE>{
[^']+ { return(ATTRIBUTE_VALUE); }
"'" { BEGIN ATTRIBUTE; }
}
<ELEMENT_CONTENT>{
[[:space:]]+ { BEGIN INITIAL; }
[^<]+ { BEGIN INITIAL; return(ELEMENT_VALUE); }
}
%%
int yywrap(){ return 1;}
int main(int argc, char *argv[])
{
yyin = fopen(argv[1], "r");
int tok;
while (tok = yylex()) {
switch (tok){
case 258:
printf("Start Tag = %s\n", yytext);
break;
case 259:
printf("End Tag = %s\n", yytext);
break;
case 260:
printf("Element Value = %s\n", yytext);
break;
case 261:
printf("Attribute Name = %s\n", yytext);
break;
case 262:
printf("Attribute Value = %s\n", yytext);
break;
case 263:
printf("JUNK = %s\n", yytext);
break;
default:
printf(" = invalid token, value = %s\n", yytext);
}
}
fclose(yyin);
return 0;
}
看看这个程序(它是 C++,但这种语言更好地说明了问题):
#include <iostream>
int main()
{
const char text[] = "Hello World!";
std::cout << text << '\n';
std::cout << text[1] << '\n';
std::cout << text + 1 << '\n';
return 0;
}
它打印:
Hello World!
e
ello World!
看到问题了吗? :-)
您将字符串的第二个字符传递给 printf
而不是传递其地址。 printf
需要内存地址并尝试将字符用作一个。
解决方法是:
printf("Start Tag = %s\n", yytext + 1);
(注意不要在任何允许空字符串的规则中使用它。)
顺便说一句,我会写一个函数,如果它们在“<”之后,也会删除空格。
我创建了一个词法分析器来标记 XML 文档。我在这条消息的底部显示词法分析器。
对于此 XML 文档:
<?xml version="1.0" encoding="UTF-8"?>
<Document version="1.0">
<message>Hello, world</message>
</Document>
词法分析器产生这个输出:
Start Tag = <Document
Attribute Name = version
Attribute Value = 1.0
Start Tag = <message
Element Value = Hello, world
End Tag = </message>
End Tag = </Document>
但是,我不希望输出是:
Start Tag = <Document
相反,我希望输出为:
Start Tag = Document
即没有<
符号。
为了实施该更改,在我的词法分析器的 main() 例程中,我更改了以下内容:
printf("Start Tag = %s\n", yytext);
对此:
printf("Start Tag = %s\n", yytext[1]);
我一做出更改,词法分析器就停止输出任何内容(即,在我做出更改后输出为空)。为什么那个微小的变化会导致没有输出?除了第一个字符之外,yytext 的值的正确输出方式是什么?
这是我的词法分析器:
%x ELEMENT_CONTENT
%x ATTRIBUTE
%x QUOTED_ATTRIBUTE_VALUE
%x APOSTROPHED_ATTRIBUTE_VALUE
%{
enum yytokentype {
START_TAG = 258,
END_TAG = 259,
ELEMENT_VALUE = 260,
ATTRIBUTE_NAME = 261,
ATTRIBUTE_VALUE = 262,
JUNK = 263
};
int yyval;
%}
%%
<INITIAL>{
"<?xml"[^?>]+"?>"[[:space:]]+ {}
">" {}
"<"[^/>[:space:]]+ { BEGIN ATTRIBUTE; return(START_TAG); }
"</"[^[:space:]]+ { return(END_TAG); }
[[:space:]]+ {}
}
<ATTRIBUTE>{
">" { BEGIN ELEMENT_CONTENT; }
"/>" { BEGIN INITIAL; }
[[:space:]]+ {}
[^[:space:]="'>/]+ { return(ATTRIBUTE_NAME); }
"=" {}
\" { BEGIN QUOTED_ATTRIBUTE_VALUE; }
"'" { BEGIN APOSTROPHED_ATTRIBUTE_VALUE; }
}
<QUOTED_ATTRIBUTE_VALUE>{
[^"]+ { return(ATTRIBUTE_VALUE); }
\" { BEGIN ATTRIBUTE; }
}
<APOSTROPHED_ATTRIBUTE_VALUE>{
[^']+ { return(ATTRIBUTE_VALUE); }
"'" { BEGIN ATTRIBUTE; }
}
<ELEMENT_CONTENT>{
[[:space:]]+ { BEGIN INITIAL; }
[^<]+ { BEGIN INITIAL; return(ELEMENT_VALUE); }
}
%%
int yywrap(){ return 1;}
int main(int argc, char *argv[])
{
yyin = fopen(argv[1], "r");
int tok;
while (tok = yylex()) {
switch (tok){
case 258:
printf("Start Tag = %s\n", yytext);
break;
case 259:
printf("End Tag = %s\n", yytext);
break;
case 260:
printf("Element Value = %s\n", yytext);
break;
case 261:
printf("Attribute Name = %s\n", yytext);
break;
case 262:
printf("Attribute Value = %s\n", yytext);
break;
case 263:
printf("JUNK = %s\n", yytext);
break;
default:
printf(" = invalid token, value = %s\n", yytext);
}
}
fclose(yyin);
return 0;
}
看看这个程序(它是 C++,但这种语言更好地说明了问题):
#include <iostream>
int main()
{
const char text[] = "Hello World!";
std::cout << text << '\n';
std::cout << text[1] << '\n';
std::cout << text + 1 << '\n';
return 0;
}
它打印:
Hello World!
e
ello World!
看到问题了吗? :-)
您将字符串的第二个字符传递给 printf
而不是传递其地址。 printf
需要内存地址并尝试将字符用作一个。
解决方法是:
printf("Start Tag = %s\n", yytext + 1);
(注意不要在任何允许空字符串的规则中使用它。)
顺便说一句,我会写一个函数,如果它们在“<”之后,也会删除空格。