0
votes

I am new to C and even more new to Flex and Bison. I am writing a simple parser, for a project. I am trying to be able to make a load command so I can load code from an external file and have the parser run it. Here is the code I have:

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;      
}

Here are the load of Errors I get, Every time I attempt to fix one I just get more.

Errors:

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

Let me know if you want the entire Bison file

1

1 Answers

1
votes

getCode is just completely wrong. That has nothing to do with Bison. Reading an entire file one character at a time is silly; concatenating each character to the end of a string has quadratic execution time since the entire string needs to be scanned for each concatenation, and in any case you never allocate any memory fir the string you're trying to construct; you never check to see if you have used all the memory allocatef to the string, and you seem to believe that a char is a one-character string, even though it should be evident from the types that a char and a char* are completely different. (That's not a complete list of the problems with that function.) strcat requires two strings, not a string and a char.

From a flex/bison perspective, since flex understands how to read input files, there is really no point reading the file yourself. All you need to do is open a FILE* and arrange for the flex-generated scanner to read it. One way to do that is shown in the Flex manual in the section on multiple input buffers. Another way would be to use a reentrant scanner and parser, and recursively call the parser.

Where you call getCode in your parser, you are assigning its return value (a const char *) to the semantic value ($$) of stmt, but stmt has the type tag nPtr, so the assignment is a type error.