-1

我正在尝试制作一个 Cminus 编译器,并专门尝试为它创建一个 AST。

在我的 step3.fl 文件中

%option noyywrap

%{
    /* Definitions and statements */
    #include "step3.tab.h"
    //extern YYSTYPE yylval;
    YYSTYPE yylval;
%}

ID      {letter}{letter}*
NUM     {digit}{digit}*
letter  [a-zA-Z]
digit   [0-9]

%option noinput nounput
%option yylineno
%option noyywrap

%%
"if"                                { return T_IF;      }
"else"                              { return T_ELSE;    }
"int"                               { return T_INT;     }
"return"                            { return T_RETURN;  }
"void"                              { return T_VOID;    }
"while"                             { return T_WHILE;   }
"+"                                 { return yytext[0]; }
"-"                                 { return yytext[0]; }
"*"                                 { return yytext[0]; }
"/"                                 { return yytext[0]; }
">"                                 { return T_GREAT;   }
">="                                { return T_GREATEQ; }
"<"                                 { return T_SMALL;   }
"<="                                { return T_SMALLEQ; }
"=="                                { return T_COMPARE; }
"!="                                { return T_NOTEQ;   }
"="                                 { return yytext[0]; }
";"                                 { return yytext[0]; }
","                                 { return yytext[0]; }
"("                                 { return yytext[0]; }
")"                                 { return yytext[0]; }
"["                                 { return yytext[0]; }
"]"                                 { return yytext[0]; }
"{"                                 { return yytext[0]; }
"}"                                 { return yytext[0]; }

{ID}        { yylval.string=strdup(yytext); return T_ID;    }
{NUM}       { yylval.value=atoi((const char *)yytext); return T_NUM;    }
%%

在我的 step3.y 文件中:

%{
    #include <stdio.h>
    #include <ctype.h>
    #include <stdlib.h>
    #include "ast.h"
    #include "symtable.h"

    static int level=0;
    static int offset=0;
    static int goffset=0;
    static int maxoffset=0;

    extern int yylex();
    extern int yyparse();
    extern char *yytext;
    extern FILE *yyin;
    void yyerror(const char* s);
    extern int yylineno;
%}
%start program

%union {
    int value;
    char *string;
    struct ASTnode * node;
    enum OPERATORS op;
}

%right "then" T_ELSE

%token  T_IF T_ELSE T_INT T_RETURN T_VOID T_WHILE 
        T_GREAT T_GREATEQ T_SMALL T_SMALLEQ T_NOTEQ T_COMPARE 

%token <value> T_NUM
%token <string> T_ID
%type <node> declaration-list declaration var-declaration fun-declaration params
%type <node> param-list param compound-stmt local-declarations statement-list statement expression-stmt
%type <node> selection-stmt iteration-stmt return-stmt expression
%type <node> var simple-expression additive-expression term factor
%type <node> call args arg-list
%type <op> relop addop mulop type-specifier

%%

program: 
                    declaration-list    {prog=$1;}  
                    ;

declaration-list: 
                    declaration-list declaration { $1->left = $2; $$ = $1; }    
                    | declaration   { $$ = $1; }                    
                    ;

declaration: 
                    var-declaration     { $$ = $1; }            
                    | fun-declaration   { $$ = $1; }            
                    ;

var-declaration: 
                    type-specifier T_ID';'
                    {
                        /* search symbol table for ID
                        insert if not found, then add the pointer from
                        insertion into the  ASTnode to have reference
                        to the symbol table entry */
                        if(Search($2,level,0))
                        {
                            fprintf(stderr,"\n\tThe name %s exists at level %d ",$2,level);
                            fprintf(stderr,"already in the symbol table\n");
                            fprintf(stderr,"\tDuplicate can.t be inserted(found in search)");
                            yyerror(" ");
                            exit(1);
                        }

                        $$=ASTCreateNode(VARDEC);
                        $$->name=$2;
                        /* we use the op to determine its type while printing*/
                        $$->op=$1;
                        $$->symbol=Insert($2,$1,0,level,1,offset,NULL);
                        $$->isType=$1;
                        offset += 1;
                        if(offset > maxoffset)
                            maxoffset = offset;
                    }
                    | type-specifier T_ID'['T_NUM']' ';'
                    {   /* search for symbol, if we find it error*/
                        if(Search($2,level,0))
                        {
                            fprintf(stderr,"\n\tThe name %s exists at level %d ",$2,level);
                            fprintf(stderr,"already in the symbol table\n");
                            fprintf(stderr,"\tDuplicate can.t be inserted(found in search)");
                            yyerror(" ");
                            exit(1);
                        }

                        $$=ASTCreateNode(VARDEC);
                        $$->name=$2;
                        /* we use the op to determine its type while printing*/
                        $$->op=$1;
                        /* value links to the NUM nod to store the dimension*/
                        $$->value=$4;
                        $$->symbol=Insert($2,$1,2,level,$4,offset,NULL);
                        $$->isType=$1;
                        offset += $4;
                        if (offset>maxoffset)
                            maxoffset = offset;
                    }
                    ;

type-specifier:     T_INT       { $$ = INTDEC; }
                    | T_VOID    { $$ = VOIDDEC; }   
                    ;

fun-declaration: 
                    type-specifier T_ID '('
                    {   /*name already used, cant make new dec*/
                        if(Search($2,level,0))
                        {
                            yyerror($2);
                            yyerror("Name already used ");
                            exit(1);
                        }
                        Insert($2,$1,1,level,1,0,NULL);
                        goffset=offset;
                        offset=2;
                        if(offset>maxoffset)
                            maxoffset = offset;
                    }
                    params
                    {   /*need the formal params to compare later */
                        (Search($2,0,0))->fparms = $5;
                    }
                    ')' compound-stmt
                     {
                        $$=ASTCreateNode(FUNCTIONDEC);
                        $$->name=$2;
                        /* we use the op to determine its type while printing*/
                        $$->op=$1;
                        /* s1 links to the params which can be void
                            or a paramList */
                        $$->s1=$5;
                        /* right links to the compund statement,
                            called a BLOCK in the enumerated type */
                        $$->right=$8;
                        /*get the symbtab entry we made earlier*/
                        $$->symbol=Search($2,0,0);
                        /*Remove symbols put in, in the function call*/
                        offset -=Delete(1);
                        level = 0;
                        $$->value=maxoffset;
                        //we change this in the symbol table because it is not used
                        //anywhere else for functions. We have access to this
                        //in calls, so we can use it to determine where the
                        //stack pointer is going to have to be
                        $$->symbol->mysize = maxoffset;
                        /*change the offset back to the global offset*/
                        offset=goffset;
                        maxoffset=0;
                    }
                    ;

params:             param-list
                    {   /* params found */
                        $$ = $1;
                    }   
                    | T_VOID
                    {   /* no params */
                        $$ = NULL;

                    }
                    ;

param-list: 
                    param-list',' param 
                    {   /* attach the param to the list */
                        $1->left=$3;
                        $$ = $1;
                    }
                    | param                 { $$ = $1; }                
                    ;

param: 
                    type-specifier T_ID
                     {   /*dont want overlap between params and vars*/
                        if(Search($2,level,0))
                        {
                           yyerror($2);
                           yyerror("\tDuplicate can.t be inserted(found in search)");
                           exit(1);
                        }
                        $$ = ASTCreateNode(PARAM);
                        $$->name=$2;
                        /* we use the op to determine its type while printing*/
                        $$->op=$1;
                        /* if value is 0 it is not an array, used for printing */
                        $$->value=0;
                        /*inherit the type*/
                        $$->isType=$1;
                        $$->symbol=Insert($2,$1,0,level+1,1,offset,NULL);
                        offset+=1;
                        if(offset>maxoffset)
                            maxoffset = offset;
                    }
                    | type-specifier T_ID'['']'
                    {
                        if(Search($2,level,0))
                        {
                           yyerror($2);
                           yyerror("\tDuplicate can.t be inserted(found in search)");
                           exit(1);
                        }
                        $$ = ASTCreateNode(PARAM);
                        $$->name=$2;
                        /* we use the op to determine its type while printing*/
                        $$->op=$1;
                        /* there was an array param */
                        $$->value=1;
                        /*inherit the type*/
                        $$->isType=$1;
                        /*2 is used for IsAFunc to show its an array ref*/
                        $$->symbol=Insert($2,$1,2,level+1,1,offset,NULL);
                        offset+=1;
                        if(offset>maxoffset)
                            maxoffset = offset;
                    }
                    ;

compound-stmt: 
                    '{' { level++; } local-declarations statement-list '}'
                    {
                        $$=ASTCreateNode(BLOCK);
                        if($3 == NULL) /*dont add decls if null*/
                            $$->right=$4;
                        else {
                            /* add the stmtList to the end of the localDecls
                            and then make the link to the right of BLOCK
                            be the whole decls and stmtList*/
                            ASTattachleft($3,$4);
                            $$->right=$3;
                        }
                        /*delete the old symbols from this block so they can
                        be used in a different block later on*/
                        offset -=Delete(level);
                        level--;
                    }
                    ;

local-declarations: 
                    local-declarations var-declaration
                    {   /*check for null, if not attach it*/
                        if($1 != NULL){
                            $1->left=$2;
                            $$=$1;
                        }
                        else
                            $$=$2;
                    }
                    |   { $$ = NULL; }
                    ;

statement-list:     
                    statement-list statement
                    {   /*check for null, if not attch it*/
                        if($1 != NULL) {
                            $1->left=$2;
                            $$=$1;
                        }
                        else
                            $$=$2;
                    }
                    |   { $$ = NULL; }
                    ;

statement:          
                    expression-stmt
                    { /*everything here is just the simplification to general stmt
                        to be put into a stmtList above */
                        $$ = $1;
                    }
                    | compound-stmt
                    {
                        $$ = $1;
                    }
                    | selection-stmt
                    {
                        $$ = $1;
                    }
                    | iteration-stmt
                    {
                        $$ = $1;
                    }
                    | return-stmt
                    {
                        $$ = $1;
                    }
                    ;

expression-stmt: 
                    expression ';'
                    {
                        $$=ASTCreateNode(EXPRSTMT);
                        $$->right=$1;
                        $$->isType=$1->isType;
                    }                   
                    | ';'   { $$ = NULL; }
                    ;

selection-stmt:
                    T_IF '('expression')' statement %prec "then"
                    {
                        $$ = ASTCreateNode(IFSTMT);
                        /* right is the expression to be evaluated*/
                        $$->right=$3;
                        /* s1 is link to statment (it can be a block)*/
                        $$->s1=$5;
                    }
                    | T_IF '('expression')' statement T_ELSE statement
                    {
                        $$ = ASTCreateNode(IFSTMT);
                        /* right is the expression to be evaluated*/
                        $$->right=$3;
                        /* s1 is link to statment (it can be a block)*/
                        $$->s1=$5;
                        /* s2 holds the link to the else statment (can be a block)*/
                        $$->s2=$7;
                    }
                    ;

iteration-stmt: 
                    T_WHILE '('expression')' statement
                    {
                        $$ = ASTCreateNode(ITERSTMT);
                        /* right holds expression to be evaluated*/
                        $$->right=$3;
                        /* s1 holds the stmt to execute, can be block*/
                        $$->s1=$5;
                    }                   
                    ;

return-stmt: 
                    T_RETURN ';'    {$$ = ASTCreateNode(RETURNSTMT);}                           
                    | T_RETURN expression';'
                    {
                        $$ = ASTCreateNode(RETURNSTMT);
                        /*expression to return*/
                        $$->s2=$2;
                    }
                    ;

expression: 
                    var '=' expression
                    {
                        /*we dont have to check both for void because if only one
                        is void there will be a type mismatch, otherwise they are
                        the same. So if one is void the other is also*/
                        if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
                        {
                            yyerror("Type mismatch or void in Assignment");
                            exit(1);
                        }
                        $$=ASTCreateNode(ASSIGN);
                        /* hold the link to the var node*/
                        $$->right=$1;
                        /* hold the link to the expression statement*/
                        $$->s1=$3;
                        /*inherit the type, already check for equivalence
                        so can just use $1*/
                        $$->isType=$1->isType;
                        $$->name=CreateTemp();
                        $$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
                        offset+=1;
                        if(offset>maxoffset)
                            maxoffset = offset;
                    }
                    | simple-expression     {$$ = $1;}
                    ;

var: 
                    T_ID
                    {
                        struct SymbTab * p;
                        if ((p=Search($1,level,1)) != NULL)
                        {
                            $$ = ASTCreateNode(IDENT);
                            $$->name=$1;
                            $$->symbol=p;
                            /*give the node op Type, based on SymbTab*/
                            $$->isType=p->Type;
                            if (p->IsAFunc == 2)
                            {
                                yyerror($1);
                                yyerror("Variable is an array, syntax error");
                            }
                        }
                        else
                        {
                            yyerror($1);
                            yyerror("undeclared variable used");
                            exit(1);
                        }
                    }
                    | T_ID '['expression']'
                    {
                        struct SymbTab * p;
                        if ((p=Search($1,level,1)) != NULL)
                        {
                            $$ = ASTCreateNode(IDENT);
                            $$->name=$1;
                            /* hold expression inside of array reference */
                            $$->right=$3;
                            $$->symbol=p;
                            /*capital Type is enum op*/
                            $$->isType=p->Type;
                            if (p->IsAFunc != 2)
                            {
                                yyerror($1);
                                yyerror("Variable is not an array, syntax error");
                            }
                        }
                        else
                        {
                            yyerror($1);
                            yyerror("undeclared variable used");
                            exit(1);
                        }
                    }
                    ;

simple-expression: 
                    additive-expression relop additive-expression
                    {  /* must ensure it is left recursive, to work properly */
                        /*we dont have to check both for void because if only one
                        is void there will be a type mismatch, otherwise they are
                        the same. So if one is void the other is also*/
                        if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
                        {
                            yyerror("Type mismatch or void in simpleExpression");
                            exit(1);
                        }
                        $$ = ASTCreateNode(EXPR);
                        $$->op=$2;
                        $$->left=$1;
                        $$->right=$3;
                        /*inherit the type, already check for equivalence
                        so can just use $1*/
                        $$->isType=$1->isType;
                        $$->name=CreateTemp();
                        $$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
                        offset+=1;
                        if(offset>maxoffset)
                            maxoffset = offset;
                    }
                    | additive-expression   {$$ = $1;}
                    ;

relop: 
                    T_SMALLEQ       { $$=LESSTHANEQUAL; }
                    | T_SMALL       { $$=LESSTHAN; }
                    | T_GREAT       { $$=GREATERTHAN; }
                    | T_GREATEQ     { $$=GREATERTHANEQUAL; }
                    | T_COMPARE     { $$=EQUAL; }
                    | T_NOTEQ       { $$=NOTEQUAL; }
                    ;

additive-expression: 
                    additive-expression addop term
                    {   /* must ensure it is left recursive, to work properly */
                        /*we dont have to check both for void because if only one
                        is void there will be a type mismatch, otherwise they are
                        the same. So if one is void the other is also*/
                        if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
                        {
                            yyerror("Type mismatch or void in additive exp");
                            exit(1);
                        }
                        $$ = ASTCreateNode(EXPR);
                        $$->op=$2;
                        $$->left=$1;
                        $$->right=$3;
                        /*inherit the type, already check for equivalence
                        so can just use $1*/
                        $$->isType=$1->isType;
                        $$->name=CreateTemp();
                        $$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
                        offset+=1;
                        if(offset>maxoffset)
                            maxoffset = offset;
                        }
                    | term  {$$ = $1;}                      
                    ;

addop:              
                    '+'     { $$ = PLUS; }
                    | '-'   { $$ = MINUS; }
                    ;

term: 
                    term mulop factor
                    {  /* must ensure it is left recursive, to work properly */
                        /*we dont have to check both for void because if only one
                        is void there will be a type mismatch, otherwise they are
                        the same. So if one is void the other is also*/
                        if (($1->isType != $3->isType) || ($1->isType == VOIDDEC))
                        {
                            yyerror("Type mismatch or void in term/factor exp");
                            exit(1);
                        }
                        $$ = ASTCreateNode(EXPR);
                        $$->op=$2;
                        $$->left=$1;
                        $$->right=$3;
                        /*inherit the type, already check for equivalence
                        so can just use $1*/
                        $$->isType=$1->isType;
                        $$->name=CreateTemp();
                        $$->symbol=Insert($$->name,$$->isType,0,level,1,offset,NULL);
                        offset+=1;
                        if(offset>maxoffset)
                            maxoffset = offset;
                    }                   
                    | factor    {$$ = $1;}                  
                    ;

mulop: 
                    '*'     { $$ = TIMES; }
                    | '/'   { $$ = DIVIDE; }
                    ;

factor: 
                    '('expression')'    {$$ = $2;}      
                    | var       { $$ = $1; }            
                    | call      { $$ = $1; }    
                    | T_NUM
                    {
                        $$=ASTCreateNode(NUMBER);
                        $$->value=$1;
                        /*numbers are always ints here*/
                        $$->isType=INTDEC;
                    }
                    ;

call: 
                    T_ID '('args')'
                    {
                        struct SymbTab * p;
                        if ((p=Search($1,0,1)) != NULL)
                        {   /*make sure symbol is a function*/
                            if(p->IsAFunc != 1)
                            {
                                yyerror($1);
                                yyerror("Is a variable, but was called as function");
                                exit(1);
                            }
                            /*have to make sure we are calling with right params*/
                            $$=ASTCreateNode(CALLSTMT);
                            /* hold the link to args in right*/
                            $$->right=$3;
                            $$->name=$1;
                            $$->symbol=p;
                            $$->isType=p->Type;
                        }
                        else
                        {
                            yyerror($1);
                            yyerror("Function not defined in symbol table");
                            exit(1);
                        }
                    }
                    ;

args: 
                    arg-list    { $$ = $1; }
                    |   { $$ = NULL; }
                    ;

arg-list: 
                    arg-list',' expression
                    {  /*attach the expressions to the tree in order
                        the use of the argList is handled above */
                        $$=ASTCreateNode(ARGLIST);
                        $$->left=$3;
                        $$->right=$1;
                    }
                    | expression
                    {
                        $$=ASTCreateNode(ARGLIST);
                        $$->right=$1;
                    }
                    ;
%%

int main(int argc, char *argv[]) {
    if (argc == 2)
        yyin = fopen(argv[1], "r");
    else {
        printf("No files - Exit\n");
        exit(1);
    }
    Display();
    yyparse();
    ASTprint(0, prog);
    return 0;
}

void yyerror(const char* s) {
    //fprintf(stderr, "%s-:%d %s\n", filename, yylineno, s);
    fprintf (stderr,"%s On Line: %d\n", s, yylineno);
}

在我的 ast.h 文件中

#ifndef ASTH
#define ASTH
#include <stdio.h>
#include <malloc.h>

/* define the enumerated types for the AST.  THis is used to tell us what
sort of production rule we came across */

/* this is a partial list of NODE types for the ASTNode */

enum ASTtype {
   PROGRAM,
   VARDEC,
   ARGLIST,
   IDENT,
   BLOCK,
   NUMBER,
   ASSIGN,
   EXPRSTMT,
   FUNCTIONDEC,
   CALLSTMT,
   EXPR,
   IFSTMT,
   ITERSTMT,
   RETURNSTMT,
   PARAM,
   STRINGNODE
};


enum OPERATORS {
   PLUS,
   MINUS,
   TIMES,
   DIVIDE,
   LESSTHANEQUAL,
   LESSTHAN,
   GREATERTHAN,
   GREATERTHANEQUAL,
   EQUAL,
   NOTEQUAL,
   INTDEC,
   VOIDDEC,
   STRINGDEC,
   null
};

/* define a type AST node which will hold pointers to AST structs that will
   allow us to represent the parsed code
*/
struct ASTnode
{
     enum ASTtype type;
     enum OPERATORS op;
     enum OPERATORS isType;
     char * name;
     char * str;
     int value;
     struct SymbTab * symbol;
     struct ASTnode *left,*right;    /* left is usually the connector for statements */
     struct ASTnode *s1,*s2 ; /* used for holding IF and WHILE components -- not very descriptive */
};


struct ASTnode *prog;

//prototypes
struct ASTnode *ASTCreateNode(enum ASTtype mytype);

void ASTattachleft(struct ASTnode *p, struct ASTnode *q);

void ASTprint(int level, struct ASTnode *p);

#endif /* of ASTH */

当我尝试使用这些命令进行编译时:

bison -d step3.y
flex step3.fl
gcc step3.tab.c lex.yy.c -lfl -o a.out

它给了我以下错误:

In file included from step3.fl:15:0:
step3.y:39:17: error: field ‘op’ has incomplete type
  enum OPERATORS op;

我在整个互联网上都查看了,找不到可能的解决方法。谁能帮我解决这个问题?

提前致谢。

4

2 回答 2

2

里面的代码%{ }只会包含在生成的 .c 文件中,不会包含在生成的头文件中。因此,当您的词法分析器包含头文件(并且以前不包含ast.h)时,您会得到联合,但不会得到 的内容ast.h,因此enum OPERATORS是不完整的类型,因为编译器没有看到OPERATORS.

在 Bison 中,通常最好使用%codeover %{ },因为它可以让您更好地控制代码的包含位置。在您的情况下,您需要包含ast.h在该%code requires部分中。从文档:

需要

  • 语言:C、C++
  • 目的:这是编写YYSTYPE和YYLTYPE所需的依赖代码的最佳位置。换句话说,它是定义 %union 指令中引用的类型的最佳位置。如果你使用#define 覆盖 Bison 的默认 YYSTYPE 和 YYLTYPE 定义,那么它也是最好的地方。但是,您应该 %define api.value.type 和 api.location.type。
  • Location(s):在 Bison 生成的 YYSTYPE 和 YYLTYPE 定义之前的解析器头文件和解析器实现文件。

所以那将是:

%code requires {
    #include "ast.h"
}
于 2018-11-04T14:58:50.957 回答
0

问题是您#include "ast.h"在 step3.fl 文件中丢失了。它应该就在该#include "step3.tab.h"行之前。

于 2018-11-04T20:50:12.487 回答