使用Flex和Bison为解析器创建输入函数

时间:2016-05-23 00:47:01

标签: c bison flex-lexer

我是C的新手,对Flex和Bison来说更新。我正在为一个项目编写一个简单的解析器。我试图能够创建一个加载命令,以便我可以从外部文件加载代码并让解析器运行它。这是我的代码:

Bison(spire.y):

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "helper.h"

/* prototypes */
nodeType *opr(int oper, int nops, ...);
nodeType *id(int i);
nodeType *con(int value);
void freeNode(nodeType *p);
int ex(nodeType *p);
int yylex(void);
void yyerror(char *s);
int sym[26]; /* symbol table */
%}

%union {
    int iValue; /* integer value */
    char sIndex; /* symbol table index */
    char *var;
    char *str;
    nodeType *nPtr; /* node pointer */

};

%token <iValue> INTEGER
%token <sIndex> VARIABLE
%token <var> VARNAME
%token <str> STRING
%token WHILE IF TELL EXITCOMM LOAD
%nonassoc IFX
%nonassoc ELSE
%left GE LE EQ NE '>' '<' BLKND
%left '+' '-'
%left '*' '/'
%nonassoc UMINUS
%type <nPtr> stmt expr stmt_list

%%

spire:
    code { exit(0); }
;    

code:
    code stmt { ex($2); freeNode($2); }
    | /* NULL */
;    

stmt:
    ';' { $$ = opr(';', 2, NULL, NULL); }
    | expr ';' { $$ = $1; }
    | EXITCOMM {exit(EXIT_SUCCESS); }
    | LOAD STRING ';' { char *f = $2; f++[strlen(f)-1] = 0; $$ = getCode(f); }

...

%%

...

const char * getCode(char *fileName){
    char ch;
    char *code;
    FILE *fp;

    fp = fopen(fileName, "r");

    if( fp == NULL )
    {
        printf("Error while opening the file %s.\n", fileName);
        return ';';
    }else{
        while((ch = fgetc(fp))!=EOF)
            code = strcat(code, ch);

        fclose(fp);
        return code;
 }

FLEX(spire.l):

%{
#include <stdlib.h>
#include "helper.h"
#include "spire.tab.h"
void yyerror(char *);
%}

%%

[a-z] {
        yylval.sIndex = *yytext - 'a';
        return VARIABLE;
 }

0 {
        yylval.iValue = atoi(yytext);
        return INTEGER;
 }

[1-9][0-9]* {
        yylval.iValue = atoi(yytext);
        return INTEGER;
 }

[-()<>^=+*/;{}~."] {
        return *yytext;
 }

'~'     return EXITCOMM;

"^^" return BLKND;
">=" return GE;
"<=" return LE;
"==" return EQ;
"!=" return NE;
"while" return WHILE;
"if" return IF;
"else" return ELSE;
"tell" return TELL;
"load" return LOAD;

[a-z][a-zA-Z0-9_]* {
        yylval.var = strdup(yytext);
        return VARNAME;
 }

\"[^"\n]*["\n] {
        yylval.str = strdup(yytext);
        return STRING;
}

[ \t\n]+ ; /* ignore whitespace */
. yyerror("Unknown character");

%%

int yywrap(void) {
    return 1;      
}

以下是我得到的错误加载,每当我尝试修复错误时,我就会得到更多错误。

错误:

spire.y: In function 'yyparse':
spire.y:56: warning: assignment makes pointer from integer without a cast
spire.y: At top level:
spire.y:112: error: conflicting types for 'getCode'
spire.y:56: note: previous implicit declaration of 'getCode' was here
spire.y: In function 'getCode':
spire.y:122: warning: return makes pointer from integer without a cast
spire.y:125: warning: passing argument 2 of 'strcat' makes pointer from integer without a cast
/usr/include/string.h:136: note: expected 'const char * __restrict__' but argument is of type 'char'
spire.y:208: error: expected declaration or statement at end of input

如果您想要整个Bison文件,请告诉我

1 个答案:

答案 0 :(得分:1)

getCode完全错了。这与野牛无关。一次读一个整个文件是愚蠢的;将每个字符连接到字符串的末尾具有二次执行时间,因为需要针对每个连接扫描整个字符串,并且在任何情况下,您永远不会为您正在尝试构造的字符串分配任何内存;你永远不会检查你是否已经将所有内存allocatef用于字符串,并且你似乎相信char是一个单字符的字符串,即使从char和char *完全是类型的字符串应该是明显的不同。 (这不是该函数问题的完整列表。)strcat需要两个字符串,而不是字符串和字符。

从flex / bison的角度来看,由于flex了解如何读取输入文件,因此自己无需阅读文件。您需要做的就是打开FILE*并安排flex生成的扫描程序读取它。一种方法是在Flex手册的多输入缓冲区一节中显示。另一种方法是使用可重入的扫描程序和解析器,并递归调用解析器。

如果在解析器中调用getCode,则将其返回值(const char *)分配给$$的语义值(stmt),但stmt具有类型标记nPtr,因此赋值是类型错误。