如何在Flex中扫描字符串,然后在野外解析它

时间:2014-09-26 21:31:54

标签: bison flex-lexer

我正在尝试解析像'x = 1;'这样的语句使用flex和bison。为此,我创建了一个符号表来存储'x'及其值1.因此,下次解析器看到类似'x = 2;'的语句时它会将符号表中x的值更新为2。 现在我的bison和flex代码适用于单字母变量(例如:x,y,a,b,c等)。但是,当我尝试将变量作为字符串(多个字符)时,程序会抛出分段错误。我不明白究竟出了什么问题,在哪里。下面是抛出Seg Fault的代码。

这是flex.l文件:

%{
#include <stdio.h>
#include "calc.tab.h"
%}

digit   ([0-9])
id      ([a-z])



%%

"print"       {       return(TOK_PRINTLN);}

"prints"    { return(TOK_PRINTSTR);}

"main()"    {return(TOK_MAIN);}
"{"         {return(TOK_LBRACE);}
"}"         {return(TOK_RBRACE);}

{digit}+    {
        sscanf(yytext, "%d", &yylval);
        return TOK_NUM;
        }
"("     { return(TOK_LPARAN);}
")"     { return(TOK_RPARAN);}
";" {   return(TOK_SEMICOLON);  }

"+" {   return(TOK_ADD);    }
"+="    {   return(TOK_ADDEQ);  }
"-" {   return(TOK_SUB);    }
"-="    {   return(TOK_SUBEQ);  }
"=" {   return(TOK_EQUAL);  }
{id}+   {
    sscanf(yylval.character,"%s",strdup(yytext));
    return (TOK_ID);
}
[ \n]   {}

.   {printf("Invalid character '%c', ignored\n", 
            yytext[0]);
            printf("Line Number %d\n", yylineno);
    }

%%

这是野牛代码.y文件:

%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Node
{
    char *sym; //changed
    int val;
    struct Node *next;
}SymTable;

SymTable *Head;

int symExists(char *c) //changed
{
    SymTable *tmp = malloc(sizeof(SymTable));
    tmp = Head;
    while(tmp != NULL)
    {
        if(!(strcmp(tmp->sym,c))) //changed
        return 1;
        tmp = tmp->next;
    }
    return 0;
}

SymTable *getNodeOf(char *c)//changed
{
    SymTable *tmp = malloc(sizeof(SymTable));
    tmp = Head;
    while(tmp != NULL)
    {
        if(!strcmp(tmp->sym,c))//changed
        return tmp;
        tmp = tmp->next;
    }
    return NULL;
}


void Insert(char *sym,int val)//changed
{
    //printf("%s\n",sym);
    //int i = getstrlen(sym);

    SymTable *tmp =(SymTable*) malloc(sizeof(SymTable));
    //printf("Here 1\n");
    //tmp->sym = (char *) malloc(50*sizeof(char));
    //printf("Here 2\n");
    /*tmp->sym=sym;*/strcpy(tmp->sym,sym);//changed
    tmp->val = val;

    if(Head == NULL)
    {
        tmp->next = NULL;
        Head = tmp;
    }
    else
    {
        if(symExists(sym))//changed
        {
            tmp = getNodeOf(sym);//changed
            tmp->val = val;
        }
        else
        {
            tmp->next = Head;
            Head = tmp;
        }
    }
    fprintf(stdout,"val:%d sym: %s\n",tmp->val,tmp->sym); //changed

}

int getTokIdVal(char *sym) //changed
{
    SymTable *tmp = malloc(sizeof(SymTable));
    tmp = Head;
    while(tmp!=NULL)
    {
        if(!strcmp(tmp->sym,sym)) //changed
        return tmp->val;
        tmp= tmp->next;
    }
    return 0;
}

int eval(int a,int b,char c,char *sym) //changed
{

    switch(c)
    {
        case '+':
        return a+b;
        break;
        case '-':
        return a-b;
        break;
        case 'n':
        return a;
        break;
        case '=':
        Insert(sym,a);
        break;
        case 'm':
        return -a;
        break;

    }
    return 0;
}


%}

%token TOK_SEMICOLON TOK_ADD TOK_SUB TOK_MUL TOK_DIV TOK_NUM TOK_PRINTLN TOK_EQUAL TOK_PRINTSTR TOK_QUOTE TOK_LPARAN TOK_RPARAN TOK_ADDEQ TOK_SUBEQ TOK_MAIN TOK_LBRACE TOK_RBRACE

%union{
        int int_val;
        char *character;//changed
}

%token <character> TOK_ID//changed


/*%type <int_val> expr TOK_NUM*/
%type <int_val> expr TOK_NUM



%left TOK_ADD TOK_SUB
%left TOK_MUL TOK_DIV

%%



stmt:
    |stmt expr_stmt
;

expr_stmt:
       expr TOK_SEMICOLON
       | TOK_PRINTLN expr TOK_SEMICOLON 
        {
            fprintf(stdout, "the value is %d\n", $2);
        }

;

expr:
    expr TOK_ADD expr
      {
          $$ = eval($1,$3,'+',NULL);
      }
    | TOK_ID TOK_ADDEQ expr
      {
          $$ = eval(getTokIdVal($1),$3,'+',NULL);
          Insert($1,$$);

      }
    | expr TOK_SUB expr
      {
          $$ = eval($1,$3,'-',NULL);
      }
    | TOK_ID TOK_SUBEQ expr
      {
          $$ = eval(getTokIdVal($1),$3,'-',NULL);
          Insert($1,$$);

      }
    | TOK_NUM
      {
        $$ = eval($1,0,'n',NULL);
      }
    | TOK_ID TOK_EQUAL expr
      {
          $$ = eval($3,0,'=',$1);

      }
    | TOK_ID
      {
         $$ = getTokIdVal($1);
      }
    | TOK_LPARAN TOK_SUB expr TOK_RPARAN
     {
         $$ = eval($3,0,'m',NULL);
     }

;



%%


int yyerror(char *s)
{
    printf("%s\n", s);

    return 0;
}

int main()
{
   yyparse();

   return 0;
}

1 个答案:

答案 0 :(得分:1)

您的符号表的链接列表代码已完全混乱 - 此代码(显示多个位置)是无意义的:

SymTable *tmp = malloc(sizeof(SymTable));
tmp = Head;

因为它为对象分配空间,但随后立即覆盖返回的指针,因此内存泄漏。在符号表中搜索时,您不需要分配任何内存,Insert只需要在表中尚未分配符号时进行分配。阅读C中链接列表的基本教程,例如this one

这句话也是无稽之谈:

sscanf(yylval.character,"%s",strdup(yytext));

它尝试从yylval.character中读取尚未设置为任何内容的内容,并覆盖您尝试返回的符号。你可能只想:

yylval.character = strdup(yytext);

这里。