词法分析器为 yylineno 给出未定义的错误

Lexical analyzer gives undefined error for yylineno

我对编译器设计还很陌生。我正在尝试迈出词法分析器的第一步,尝试 运行 以下代码。

%{
#include <stdlib.h>
#include <stdio.h>
#include "symboltable.h"
#include "tokens.h"

entry_t** symbol_table;
entry_t** constant_table;
int cmnt_strt = 0;


%}
letter [a-zA-Z]
digit [0-9]
ws  [ \t\r\f\v]+
identifier (_|{letter})({letter}|{digit}|_){0,31}
hex [0-9a-f]

 /* Exclusive states */
%x CMNT
%x PREPROC

%%
  /* Keywords*/
"int"                             {printf("\t%-30s : %3d\n",yytext,INT);}
"long"                            {printf("\t%-30s : %3d\n",yytext,LONG);}
"long long"                       {printf("\t%-30s : %3d\n",yytext,LONG_LONG);}
"short"                           {printf("\t%-30s : %3d\n",yytext,SHORT);}
"signed"                          {printf("\t%-30s : %3d\n",yytext,SIGNED);}
"unsigned"                        {printf("\t%-30s : %3d\n",yytext,UNSIGNED);}
"for"                             {printf("\t%-30s : %3d\n",yytext,FOR);}
"break"                           {printf("\t%-30s : %3d\n",yytext,BREAK);}
"continue"                        {printf("\t%-30s : %3d\n",yytext,CONTINUE);}
"if"                              {printf("\t%-30s : %3d\n",yytext,IF);}
"else"                            {printf("\t%-30s : %3d\n",yytext,ELSE);}
"return"                          {printf("\t%-30s : %3d\n",yytext,RETURN);}

{identifier}                      {printf("\t%-30s : %3d\n", yytext,IDENTIFIER);
                                  insert( symbol_table,yytext,IDENTIFIER );}
{ws}                              ;
[+\-]?[0][x|X]{hex}+[lLuU]?        {printf("\t%-30s : %3d\n", yytext,HEX_CONSTANT);
                                                    insert( constant_table,yytext,HEX_CONSTANT);}
[+\-]?{digit}+[lLuU]?              {printf("\t%-30s : %3d\n", yytext,DEC_CONSTANT);
                                                    insert( constant_table,yytext,DEC_CONSTANT);}
"/*"                              {cmnt_strt = yylineno; BEGIN CMNT;}
<CMNT>.|{ws}                      ;
<CMNT>\n                          {yylineno++;}
<CMNT>"*/"                        {BEGIN INITIAL;}
<CMNT>"/*"                        {printf("Line %3d: Nested comments are not valid!\n",yylineno);}
<CMNT><<EOF>>                     {printf("Line %3d: Unterminated comment\n", cmnt_strt); yyterminate();}
^"#include"                       {BEGIN PREPROC;}
<PREPROC>"<"[^<>\n]+">"            {printf("\t%-30s : %3d\n",yytext,HEADER_FILE);}
<PREPROC>{ws}                       ;
<PREPROC>\"[^"\n]+\"              {printf("\t%-30s : %3d\n",yytext,HEADER_FILE);}
<PREPROC>\n                       {yylineno++; BEGIN INITIAL;}
<PREPROC>.                        {printf("Line %3d: Illegal header file format \n",yylineno);}
"//".*                            ;

\"[^\"\n]*\"     {

  if(yytext[yyleng-2]=='\') /* check if it was an escaped quote */
  {
    yyless(yyleng-1);       /* push the quote back if it was escaped */
    yymore();
  }
  else
  insert( constant_table,yytext,STRING);
 }

\"[^\"\n]*$                     {printf("Line %3d: Unterminated string %s\n",yylineno,yytext);}
{digit}+({letter}|_)+           {printf("Line %3d: Illegal identifier name %s\n",yylineno,yytext);}
\n                              {yylineno++;}
"--"                            {printf("\t%-30s : %3d\n",yytext,DECREMENT);}
"++"                            {printf("\t%-30s : %3d\n",yytext,INCREMENT);}
"->"                            {printf("\t%-30s : %3d\n",yytext,PTR_SELECT);}
"&&"                            {printf("\t%-30s : %3d\n",yytext,LOGICAL_AND);}
"||"                            {printf("\t%-30s : %3d\n",yytext,LOGICAL_OR);}
"<="                            {printf("\t%-30s : %3d\n",yytext,LS_THAN_EQ);}
">="                            {printf("\t%-30s : %3d\n",yytext,GR_THAN_EQ);}
"=="                            {printf("\t%-30s : %3d\n",yytext,EQ);}
"!="                            {printf("\t%-30s : %3d\n",yytext,NOT_EQ);}
";"                             {printf("\t%-30s : %3d\n",yytext,DELIMITER);}
"{"                             {printf("\t%-30s : %3d\n",yytext,OPEN_BRACES);}
"}"                             {printf("\t%-30s : %3d\n",yytext,CLOSE_BRACES);}
","                             {printf("\t%-30s : %3d\n",yytext,COMMA);}
"="                             {printf("\t%-30s : %3d\n",yytext,ASSIGN);}
"("                             {printf("\t%-30s : %3d\n",yytext,OPEN_PAR);}
")"                             {printf("\t%-30s : %3d\n",yytext,CLOSE_PAR);}
"["                             {printf("\t%-30s : %3d\n",yytext,OPEN_SQ_BRKT);}
"]"                             {printf("\t%-30s : %3d\n",yytext,CLOSE_SQ_BRKT);}
"-"                             {printf("\t%-30s : %3d\n",yytext,MINUS);}
"+"                             {printf("\t%-30s : %3d\n",yytext,PLUS);}
"*"                             {printf("\t%-30s : %3d\n",yytext,STAR);}
"/"                             {printf("\t%-30s : %3d\n",yytext,FW_SLASH);}
"%"                             {printf("\t%-30s : %3d\n",yytext,MODULO);}
"<"                             {printf("\t%-30s : %3d\n",yytext,LS_THAN);}
">"                             {printf("\t%-30s : %3d\n",yytext,GR_THAN);}
.                               {printf("Line %3d: Illegal character %s\n",yylineno,yytext);}

%%

int yywrap(){ return 1;}

int main()
{
  yyin=fopen("testcases/test-case-1.c","r");
  symbol_table=create_table();
  constant_table=create_table();
  yylex();
  printf("\n\tSymbol table");
  display(symbol_table);
  printf("\n\tConstants Table");
  display(constant_table);
  printf("NOTE: Please refer tokens.h for token meanings\n");
}

我尝试 运行 它使用:

flex lexer.l
gcc lex.yy.c -o lexrun

这给了我一个错误,因为

lexer.l: In function 'yylex':
lexer.l:46:14: error: 'yylineno' undeclared (first use in this function)
 "/*"                              {cmnt_strt = yylineno; BEGIN CMNT;}
              ^~~~~~~~
lexer.l:46:14: note: each undeclared identifier is reported only once for each function it appears in

我在网上尝试了很多东西,比如添加

extern int yylineno;

这开始出现另一个错误

 undefined reference to `yylineno'

我已经安装了 Flex 版本 2.5.4 并且 运行 在 Vscode 中安装了这个。 任何克服这一问题的澄清将不胜感激。提前致谢。

如果你想让 flex 跟踪你需要添加的行号

%option yylineno

你的 flex 序言。

我还建议如下:

  • %option noinput nounput
    

    这将允许您在没有编译器警告的情况下编译生成的扫描器(Always 使用 -Wall 编译,甚至生成的代码,并修复报告的任何警告。)

  • %option noyywrap
    

    这避免了定义 yywrap

    的需要
  • %option  nodefualt
    

    如果您没有针对每个可能的输入的规则,它会警告您。


最后一点,extern int yylineno; 不起作用,因为 extern 表示“此变量在不同的翻译单元中定义”,并且您的代码中没有其他翻译单元。我假设您在讨论旨在与扫描仪链接在一起的不同文件时发现了这一点。 (如果您发现的地方建议将 extern 声明放在 .l 文件中,您需要将其作为信息来源丢弃。)

如果这是您第一次尝试使用多个源文件编写 C 应用程序,您可能应该花几分钟时间回顾一下如何在 C 中链接多个文件。这将为您节省很多后来的挫败感。