如何在 flex 中使用 yylval

How to use yylval in flex

我正尝试在 windows 上使用 FLEX 构建一个词法分析器。 我总是收到错误消息:

"undefined reference to `yylval'"

我将 yylval 声明为 extern 类型,其中所有定义如下:

  %option noyywrap
    %{
        #include<stdio.h>
        #include<stdlib.h>
        #include "tokens.h"
        int nline = 1;
        int size_token_array = 100;
        int number_of_tokens_in_array = 0;
        int inc_token_array = 50;
        token *token_store ;
        extern yylval;

    %}
    delim [ \t]
    delim_nl [\n]
    ws {delim}+
    nl {delim_nl}+
    letter [a-z]
    digit [0-9]
    id {letter}(letter.digit)*
    int_num (0|([+-]?([1-9]{digit}*)))
    real_num [+-]?{digit}+(\.{digit}+)
    rel_op ">"|"<"|"<="|">="|"=="|"!="
    binary_ar_op "+"|"-"|"*"|"/"|"="
    task_id {letter}(letter+digit)*
    signal_id {letter}(letter+digit)*

    %%
    "parbegin" {create_and_store_token(TOKEN_PARBEGIN,yytext,nline); return 1;}
    "parend" {create_and_store_token(TOKEN_PAREND,yytext,nline); return 1;}
    "task" {create_and_store_token(TOKEN_TASK,yytext,nline); return 1;} 
    "{" {create_and_store_token('{',yytext,nline); return 1;} 
    "}" {create_and_store_token('}',yytext,nline); return 1;}
    "begin" {create_and_store_token(TOKEN_BEGIN,yytext,nline); return 1;}  
    "end" {create_and_store_token(TOKEN_END,yytext,nline); return 1;} 
    "integer" {create_and_store_token(TOKEN_INTEGER,yytext,nline); return 1;} 
    "real" {create_and_store_token(TOKEN_REAL,yytext,nline); return 1;}
    "||"  {create_and_store_token(TOKEN_PARALLEL,yytext,nline); return 1;}
    ";" {create_and_store_token(';',yytext,nline); return 1;} 
    "," {create_and_store_token(',',yytext,nline); return 1;} 
    "do" {create_and_store_token(TOKEN_DO,yytext,nline); return 1;} 
    "until" {create_and_store_token(TOKEN_UNTIL,yytext,nline); return 1;} 
    "od" {create_and_store_token(TOKEN_OD,yytext,nline); return 1;}  
    "send" {create_and_store_token(TOKEN_SEND,yytext,nline); return 1;} 
    "accept" {create_and_store_token(TOKEN_ACCEPT,yytext,nline); return 1;}  
    "(" {create_and_store_token('(',yytext,nline); return 1;} 
    ")" {create_and_store_token(')',yytext,nline); return 1;} 
    "<" {create_and_store_token(LT,yytext,nline); yylval=rel_op; return 1;} 
    ">" {create_and_store_token(GT,yytext,nline); yylval=rel_op; return 1;}  
    "<=" {create_and_store_token(LE,yytext,nline); yylval=rel_op; return 1;}  
    ">=" {create_and_store_token(GE,yytext,nline); yylval=rel_op; return 1;}  
    "==" {create_and_store_token(EQ,yytext,nline); yylval=rel_op; return 1;}  
    "!=" {create_and_store_token(NE,yytext,nline); yylval=rel_op; return 1;} 
    "*" {create_and_store_token('*',yytext,nline); yylval=binary_ar_op; return 1;}  
    "/" {create_and_store_token('/',yytext,nline); yylval=binary_ar_op; return 1;}  
    "+" {create_and_store_token('+',yytext,nline); yylval=binary_ar_op; return 1;}  
    "-" {create_and_store_token('-',yytext,nline); yylval=binary_ar_op; return 1;} 
    "=" {create_and_store_token('=',yytext,nline); yylval=binary_ar_op; return 1;} 
    {ws} ;
    {nl} nline++;
    id {create_and_store_token(TOKEN_ID,yytext,nline); return 1;} 
    int_num {create_and_store_token(TOKEN_INT_NUM,yytext,nline); return 1;}  
    real_num {create_and_store_token(TOKEN_REAL_NUM,yytext,nline); return 1;}  
    binary_ar_op {create_and_store_token(TOKEN_AR_OP,yytext,nline); return 1;}  
    "task_id" {create_and_store_token(TOKEN_TASK_ID,yytext,nline); return 1;}  
    "signal_id" {create_and_store_token(TOKEN_SIGNAL_ID,yytext,nline); return 1;}  

    %%
    int main()
    {
        token_store = (token*)calloc(size_token_array,sizeof(token));
        free(token_store);
        return 0;

    }

    void create_and_store_token(int token_type,char* token_lexeme,int line_number){

        token new_token;
        new_token.ivalue = token_type;
        new_token.lexema = token_lexeme;
        new_token.line_number = line_number;

        if(size_token_array == (number_of_tokens_in_array-10)){

          token_store = (token*)realloc(token_store,inc_token_array*sizeof(token));
          size_token_array+=inc_token_array;
          number_of_tokens_in_array++;
          token_store[number_of_tokens_in_array]= new_token;

        }
        else{
          token_store[number_of_tokens_in_array]= new_token;
          number_of_tokens_in_array++;

        }
    }

    int nextToken(){
       return yylex();
    }

    void backToken(){
        token_store[number_of_tokens_in_array].ivalue = 0;
        token_store[number_of_tokens_in_array].lexema = "";
        token_store[number_of_tokens_in_array].line_number = 0;
        number_of_tokens_in_array--;
    }

有人知道我应该如何解决这个问题吗?

extern yylval; 表示 yylval 在别处定义。所以你必须这样做。

通常它是在yacc/bison生成的解析器中定义的,所以当你link扫描器和解析器时可以解析这个名字。如果您不使用 bison/yacc,则必须自己定义 yylval。 (如果你真的需要它。你的代码并没有给出你需要它做什么的提示。)

顺便说一下,您的代码还有很多其他问题。一个特别明显的是,在扫描器移动到下一个标记后,您不能使用指针 yytext 的值。如果您需要 yytext 指向的字符串的永久副本,您需要制作自己的副本(并在不再需要时释放为该副本分配的内存。)

您的许多正则表达式也不正确。宏使用 ("definitions") 必须用大括号括起来,所以

id {create_and_store_token(TOKEN_ID,yytext,nline); return 1;} 

不会符合您的预期;它只会匹配两个字符序列id。将其更改为 {id} 是一个开始, 但是 id 的定义也不正确。

就我个人而言,我避免使用宏,因为它们不会为代码增加任何价值,IMO;他们经常造成混乱。例如,您对 letter 的定义仅包含小写字母,这对于阅读您的代码的人来说根本不是显而易见的。最好使用 Posix 字符 类,它不需要定义且含义明确:[[: alpha:]] 表示字母,[[:lower:]] 表示小写字母,[[:alnum:]] 用于字母或数字等