如何输出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);

(注意不要在任何允许空字符串的规则中使用它。)

顺便说一句,我会写一个函数,如果它们在“<”之后,也会删除空格。