Error: request for member " " in something not a structure or union (Yacc)

Error: request for member " " in something not a structure or union (Yacc)

我正在尝试制作一个 c-minus 编译器,但我必须制作一个抽象语法树和一个符号 Table。还要处理错误是否有可能在没有抽象语法树的情况下进行错误处理? 这是我在终端中的输出:

syntan.y: In function ‘yyparse’:
syntan.y:70:64: warning: assignment to ‘ASTnode *’ {aka ‘struct ASTnodetype *’} from incompatible pointer type ‘int *’ [-Wincompatible-pointer-types]
   70 | program:                declaration_list                { prog = ; }
      |                                                                ^
syntan.y:73:76: error: request for member ‘left’ in something not a structure or union
   73 | declaration_list:       declaration_list declaration    {  -> left = ; $$ = ; }
      |                                                                            ^~
syntan.y:86:36: error: ‘VOIDDEC’ undeclared (first use in this function)
   86 |              if ( != VOIDDEC &&  != INTDEC)
      |                                    ^~~~~~~
syntan.y:86:36: note: each undeclared identifier is reported only once for each function it appears in                        

yacc 文件

%{
    #include <math.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include "y.tab.h"
    #include "asttree.h"
    #include "symboltable.h"

    void yyerror(const char *s);
    extern int yylex(void);
    extern int yyparse(void);
    extern char *yytext;
    extern FILE *yyin;

    char filename[50];
    static int level = 0;
    static int offset = 0;
    static int goffset = 0;
    static int maxoffset = 0;
    
    void yyerror(const char* s);
    extern int yylineno;
%}

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

%start program

%token<intv>T_NUM
%token IF WHILE ELSE
%token RETURN INT VOID 
%token GREATEQ LESS SMALLEQ EQUALITY NOTEQ BIGGER
%token TIMES DIVIDE PLUS MINUS EQUAL QUESTIONM COMMA
%token LBRAC RBRAC LPAR RPAR LCURLY RCURLY
%token<string>T_ID

%left PLUS MINUS
%left TIMES DIVIDE
%left LPAR RPAR
%right ELSE

%type<node> declaration_list declaration var_declaration 
%type<node> program
%type<node> fun_declaration additive_expression
%type<node> params param_list param
%type<node> compound_stmt local_declarations statement_list statement
%type<node> expression_stmt selection_stmt iteration_stmt return_stmt
%type<node> expression var simple_expression term factor call args arg_list
%type<op> relop addop mulop type_specifier 

%%
program:                declaration_list                { prog = ; } 
       ;

declaration_list:       declaration_list declaration    {  -> left = ; $$ = ; }
                |       declaration                     { $$ = ;                  }
                ;

declaration:            var_declaration                 { $$ = ;  }
           |            fun_declaration                 { $$ = ;  }
           ;
               

var_declaration:        type_specifier T_ID QUESTIONM           
                        {
                            if(Search(, level, 0))
                                yyerror("Redefined variable declaration");
                            if ( != VOIDDEC &&  != INTDEC)
                                yyerror("Invalid type specifier");

                            $$ = ASTCreateNode(VARDEC);
                            $$ -> name = ;
                            /* we use the op to determine its type while printing*/
                            $$ -> op = ;
                            $$ -> symbol = Insert(, , 0, level, 1, offset, NULL);
                            $$ -> isType = ;
                            offset += 1;
                            if(offset > maxoffset)
                                maxoffset = offset;
                        }
               |        type_specifier T_ID LBRAC T_NUM RBRAC QUESTIONM  
                        {
                            if(Search(, level, 0))
                                yyerror("Redefined variable declaration");

                            $$ = ASTCreateNode(VARDEC);
                            $$ -> name = ;
                            $$ -> op = ;
                          
                            $$ -> value = ;
                            $$ -> symbol = Insert(, , 2, level, , offset, NULL);
                            $$ -> isType = ;
                            offset += ;
                            if (offset > maxoffset)
                                maxoffset = offset;
                        }
               ;

type_specifier:         INT     { $$ = INTDEC;  }
              |         VOID    { $$ = VOIDDEC; }
              ;
fun_declaration:        type_specifier T_ID LPAR
                        {   
                            if(Search(, level, 0))
                                yyerror("Redefined function declaration");
                            Insert(, , 1, level, 1, 0, NULL);
                            goffset = offset;
                            offset = 2;
                            if(offset > maxoffset)
                                maxoffset = offset;
                        }
                        params
                        { 
                            (Search(, 0, 0)) -> fparms = ;
                        }
                        RPAR compound_stmt
                        {
                            $$ = ASTCreateNode(FUNCTIONDEC);
                            $$ -> name = ;
                            /* we use the op to determine its type while printing*/
                            $$ -> op = ;
                            /* s1 links to the params which can be void
                                or a paramList */
                            $$ -> s1 = ;
                            /* right links to the compund statement,
                                called a BLOCK in the enumerated type */
                            $$ -> right = ;
                            /*get the symbtab entry we made earlier*/
                            $$ -> symbol = Search(, 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  { $$ = ;   }
      |                 VOID        { $$ = NULL; }
      ;
 
param_list:             param_list COMMA param
                        {  
                             -> left = ;
                            $$ = ;
                        }
          |             param   { $$ = ; }
          ;
 
param:                  type_specifier T_ID
                        {  
                            if(Search(, level, 0))
                                yyerror("Redefined variable declaration");
                            $$ = ASTCreateNode(PARAM);
                            $$ -> name = ;
                            /* we use the op to determine its type while printing*/
                            $$ -> op = ;
                            /* if value is 0 it is not an array, used for printing */
                            $$ -> value = 0;
                            /*inherit the type*/
                            $$ -> isType = ;
                            $$ -> symbol = Insert(, , 0, level+1, 1, offset, NULL);
                            offset += 1;
                            if(offset > maxoffset)
                                maxoffset = offset;
                        }
     |                  type_specifier T_ID LBRAC RBRAC
                        {
                            if(Search(, level, 0))
                                yyerror("Redefined variable declaration");
                            $$ = ASTCreateNode(PARAM);
                            $$ -> name = ;
                            /* we use the op to determine its type while printing*/
                            $$ -> op = ;
                            /* there was an array param */
                            $$ -> value = 1;
                            /*inherit the type*/
                            $$ -> isType = ;
                            /*2 is used for IsAFunc to show its an array ref*/
                            $$ -> symbol = Insert(, , 2, level+1, 1, offset, NULL);
                            offset += 1;
                            if(offset > maxoffset)
                                maxoffset = offset;
                        }
     ;
     
compound_stmt:          LCURLY 
                        { level++; }
                        local_declarations statement_list RCURLY
                        {
                            $$ = ASTCreateNode(BLOCK);
                            if(  == NULL )
                                $$ -> right = ;
                            else {
                                ASTattachleft(, );
                                $$ -> right = ;
                            }
                            offset -= Delete(level);
                            level--;
                        }
             ;

local_declarations:     local_declarations var_declaration
                        {  
                            if( != NULL)
                            {
                                 -> left = ;
                                $$ = ;
                            }
                            else
                                $$ = ;
                        }
                  |     { $$ = NULL; }
                  ;
                
statement_list:         statement_list statement
                        {   
                            if(  != NULL ) 
                            {
                                 -> left = ;
                                $$ = ;
                            }
                            else
                                $$ = ;
                        }
              |         { $$ = NULL; }
              ;
              
statement:              expression_stmt { $$ = ; }
         |              compound_stmt   { $$ = ; }
         |              selection_stmt  { $$ = ; }
         |              iteration_stmt  { $$ = ; } 
         |              return_stmt     { $$ = ; }
         ;

expression_stmt:        expression QUESTIONM
                        {
                            $$ = ASTCreateNode(EXPRSTMT);
                            $$ -> right = ;
                            $$ -> isType =  -> isType;
                        }
               |        QUESTIONM   { $$ = NULL; }
               ;
              
selection_stmt:         IF LPAR expression RPAR statement
                        {
                            $$ = ASTCreateNode(IFSTMT);
                            $$ -> right = ;
                            $$ -> s1 = ;       
                        }
              |         IF LPAR expression RPAR statement ELSE statement  
                        {  
                            $$ = ASTCreateNode(IFSTMT);
                            $$ -> right = ;
                            $$ -> s1 = ;
                            $$ -> s2 = ; 
                        }
              ;

iteration_stmt:         WHILE LPAR expression RPAR statement
                        { 
                            $$ = ASTCreateNode(ITERSTMT);
                            $$ -> right = ;
                            $$ -> s1 = ;                    
                        }
              ;

return_stmt:            RETURN QUESTIONM    { $$ = ASTCreateNode(RETURNSTMT); }
           |            RETURN expression QUESTIONM 
                        { 
                            $$ = ASTCreateNode(RETURNSTMT);
                            $$ -> s2 = ;                      
                        }
           ;

expression:             var EQUAL expression
                        {
                            if (( -> isType !=  -> isType) || ( -> isType == VOIDDEC))
                                yyerror("Incompatible types in assignment");
                            $$ = ASTCreateNode(ASSIGN);
                            /* hold the link to the var node*/
                            $$ -> right = ;
                            /* hold the link to the expression statement*/
                            $$ -> s1 = ;
                            /*inherit the type, already check for equivalence so can just use */
                            $$ -> isType =  -> isType;
                            $$ -> name = CreateTemp();
                            $$ -> symbol = Insert($$ -> name, $$ -> isType, 0, level, 1, offset, NULL);
                            offset += 1;
                            if(offset > maxoffset)
                                maxoffset = offset;
                        }
          |             simple_expression   { $$ = ; }
          ;

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

simple_expression:      additive_expression relop additive_expression   
                        {
                            if (( -> isType !=  -> isType) || ( -> isType == VOIDDEC))
                                yyerror("Type mismatch or void in simpleExpression");
                            $$ = ASTCreateNode(EXPR);
                            $$ -> op = ;
                            $$ -> left = ;
                            $$ -> right = ;
                            /*inherit the type, already check for equivalence so can just use */
                            $$ -> isType =  -> isType;
                            $$ -> name = CreateTemp();
                            $$ -> symbol = Insert($$ -> name, $$ -> isType, 0, level, 1, offset, NULL);
                            offset += 1;
                            if(offset > maxoffset)
                                maxoffset = offset;
                        }
                 |      additive_expression     { $$ = ; }
                 ;

relop:                  BIGGER   { $$ = BIGGER; }
     |                  LESS     { $$ = LESS;        }
     |                  SMALLEQ  { $$ = SMALLEQ;     }
     |                  EQUALITY { $$ = EQUAL;       }
     |                  NOTEQ    { $$ = NOTEQ;       }
     |                  GREATEQ  { $$ = GREATEQ;     }
     ;    

additive_expression:    additive_expression addop term  
                        { 
                            if (( -> isType !=  -> isType) || ( -> isType == VOIDDEC))
                                yyerror("Type mismatch or void in additive exp");
                            $$ = ASTCreateNode(EXPR);
                            $$ -> op = ;
                            $$ -> left = ;
                            $$ -> right = ;
                            /*inherit the type, already check for equivalence so can just use */
                            $$ -> isType =  -> isType;
                            $$ -> name = CreateTemp();
                            $$ -> symbol = Insert($$ -> name, $$ -> isType, 0, level, 1, offset, NULL);
                            offset += 1;
                            if(offset > maxoffset)
                                maxoffset = offset; 
                        }
                   |    term    { $$ = ;    }
                   ;
                   
addop:                  PLUS    { $$ = PLUS;  }
     |                  MINUS   { $$ = MINUS; }
     ;                    

term:                   term mulop factor   
                        {  
                            if (( -> isType !=  -> isType) || ( -> isType == VOIDDEC))
                                yyerror("Type mismatch or void in term/factor exp");
                            $$ = ASTCreateNode(EXPR);
                            $$ -> op = ;
                            $$ -> left = ;
                            $$ -> right = ;
                            /*inherit the type, already check for equivalence so can just use */
                            $$ -> isType =  -> isType;
                            $$ -> name = CreateTemp();
                            $$ -> symbol = Insert($$ -> name, $$ -> isType, 0, level, 1, offset, NULL);
                            offset += 1;
                            if(offset > maxoffset)
                                maxoffset = offset;    
                        }
    |                   factor  { $$ = ;     }
    ;

mulop:                  TIMES   { $$ = TIMES;  }
     |                  DIVIDE  { $$ = DIVIDE; }
     ;

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

call:                   T_ID LPAR args RPAR     
                        {  
                            struct SymbTab * p;
                            if ((p = Search(, 0, 1)) != NULL)
                            {   /*make sure symbol is a function*/
                                if(p -> IsAFunc != 1)
                                    yyerror("Is a variable, but was called as function");
                                if (compareFormals(p -> fparms, ) != 1)
                                    yyerror("Wrong type of arguments");
                                $$ = ASTCreateNode(CALLSTMT);
                                /* hold the link to args in right*/
                                $$ -> right = ;
                                $$ -> name = ;
                                $$ -> symbol = p;
                                $$ -> isType = p -> Type;
                            }
                            else
                                yyerror("Call to undefined function"); 
                        }
    ;
    
args:                   arg_list     { $$ = ;   }
    |                                { $$ = NULL; }
    ;
             
arg_list:               arg_list COMMA expression   
                        {
                            $$ = ASTCreateNode(ARGLIST);
                            $$ -> left = ;
                            $$ -> right = ;  
                        }
  
        |               expression                  
                        {  
                            $$ = ASTCreateNode(ARGLIST);
                            $$ -> right = ;    
                        }  
                     
    ;

%%

** AST 文件**

#include "asttree.h"

int lineCounter = 0;
int labelCounter = 0;
int tempCounter = 0;


ASTnode *ASTCreateNode(enum ASTtype mytype)
{
    ASTnode * p;
    p = (ASTnode *)malloc(sizeof(ASTnode));
    p -> type = mytype;
    p -> left = NULL;
    p -> right = NULL;
    p -> s1 = NULL;
    p -> s2 = NULL;
    p -> value = 0;
    p -> name = NULL;
    p -> str = NULL;
    p -> symbol = NULL;
    p -> isType = null;
    return(p);
}

/* attach q to the left most part of p */
void ASTattachleft(ASTnode* p,ASTnode* q)
{
    while (p -> left != NULL)
        p = p -> left;
    p -> left = q; /*add on the left side of the tree*/
}

/*
 *  Printing Tabbing
 */
void PT(int howmany)
{
    int i;
    for (i = 0; i < howmany; i++)
        printf(" ");
}

/* AST PRINT */
void ASTprint(int level, ASTnode* p) 
{
    if (p == NULL ) 
        return;
    else 
    {
        PT(level);
        switch (p->type) 
        {
            case VARDEC :
                printf("Variable  "); //one per ast node type
                if ((p -> op) == INTDEC)
                    printf("INT ");

                if (p -> op == VOIDDEC)
                    printf("VOID ");
 
                printf("%s\n", p -> name);
                if (p -> value > 0) 
                {//is an array 
                    printf("[%d]\n", p -> value);
                }
                lineCounter++;
                break;

            case FUNCTIONDEC:
                if (p -> op == INTDEC)
                    printf("INT ");
                    
                if (p -> op == VOIDDEC)
                    printf("VOID ");
                    
                printf("FUNCTION %s \n", p -> name);
                
                if (p -> s1 == NULL) 
                {
                    PT(level + 2);
                    printf( "(VOID)\n" );
                }
                else 
                {
                    PT(level + 2);
                    printf("( \n");
                    ASTprint(level + 2, p -> s1);
                    PT(level + 2);
                    printf(") \n");
                }
                ASTprint(level + 2,p -> right);
                
                break;

            case EXPR: printf("EXPR ");
                if (p -> name != NULL)
                    printf("  %s = ", p->name);
                ASTnode* node1 = p -> right;
                ASTnode* node2 = p -> left;
                
                switch (p -> op)
                {
                    case PLUS: 
                        printf("+");
                        break;

                    case MINUS: 
                        printf("-");
                        break;

                    case TIMES: 
                        printf("*");
                        break;

                    case DIVIDE: 
                        printf("/");
                        break;

                    case SMALLEQ: 
                        printf("<=");
                        break;

                    case LESS: 
                        printf("<");
                        break;

                    case BIGGER: 
                        printf(">");
                        break;

                    case GREATEQ: 
                        printf(">=");
                        break;

                    case NOTEQ: 
                        printf("!=");
                        break;

                    case EQUAL: 
                        printf("==");
                        break;

                    case INTDEC:
                    case VOIDDEC:
                    case null:
                    break;

               }
               printf("\n");
               ASTprint(level + 1, p -> left);
               ASTprint(level + 1, p -> right);
               break;

            case  RETURNSTMT:
                printf("Return statement\n");
                ASTprint(level + 1, p -> right);
                break;

            case IDENT:
                printf("IDENTIFIER %s\n", p->name);
                if (p -> right != NULL)
                {
                    PT(level);
                    printf("Array reference [\n");
                    ASTprint(level + 1, p -> right);
                    PT(level);
                    printf("] end array\n");
                }
                break;

            case BLOCK:
                printf("compound_stmt\n");
                ASTprint(level + 1, p -> right);
                break;

            case ASSIGN:
                printf("Assignment STATEMENT\n");
                ASTprint(level + 1, p -> right);
                ASTprint(level + 1, p -> s1);
                break;

            case NUMBER:
                printf("NUMBER with value %d\n", p->value);
                break;

            case ITERSTMT:
                printf("WHILE STATEMENT\n");

                ASTprint(level + 1, p -> right);
                printf("\n");

                ASTprint(level + 1, p -> s1);
                printf("\n");
                break;

            case PARAM:
                printf("PARAMETER ");
                printf(" %s ", p -> name);
                if(p -> value == -1)
                    printf("[]");

                printf("\n");
                break;

            case IFSTMT:
                printf("IF STATEMENT\n");

                ASTprint(level + 1, p -> right);
                printf("\n");

                ASTprint(level + 1, p -> s1);
                printf("\n");

                if(p -> s2 != NULL)
                {
                    PT(level);
                    printf("ELSE \n");
                    ASTprint(level + 2, p -> s2);
                }
                break;

            case CALLSTMT:
                printf("Function Call  %s\n" , p ->name);
                if (p -> right != NULL)
                {
                    ASTprint(level + 2, p -> right);
                    printf("\n");
                } else {
                    PT(level + 2);
                    printf("(VOID)\n");
                }
                break;
            
            case ARGLIST:
                printf("ARG\n");
                ASTnode* node4 = p -> right;
                ASTprint(level + 1, p -> right);
                break;

            case EXPRSTMT:
                printf("Expression Statement\n");
                ASTnode* node3 = p -> right;
                ASTprint(level + 1, p -> right);
                break;

            default: printf("Unknown type in ASTprint\n");
                break;
        }
        if (p -> type != EXPR)
            ASTprint(level, p -> left);
    }
}

/* 
 *  COMPAREFORMALS
 *  Used to compare parms declared to the ones used to call 
 */
int compareFormals(ASTnode * p, ASTnode *q) 
{
    if((p == NULL) && (q == NULL))
        return(1);                                  //they were both void
    else if ((p == NULL) || (q == NULL))
        return (0);                                 //one is void, already checked for both so p!=q
    else if(p -> isType == q -> right -> isType)
        compareFormals(p -> left, q -> left);       //check the next param
    else
        return(0);
}

任何建议都会有帮助!

尽管问题中粘贴了数百行代码,但我不确定是否真的足够继续下去,特别是因为您既没有包含收到的所有错误消息,也没有包含头文件.所以这更像是一个猜测。在编写大量代码之前尝试编译代码通常是个好主意,特别是如果您将被要求提供一个 minimal 可重现的示例。但这都是题外话。

我在你的语法文件中注意到,就在开头,你的包含:

    #include "y.tab.h"
    #include "asttree.h"
    #include "symboltable.h"

第一个是错误的。这是 Bison 生成的头文件,Bison 将把该文件中的所有内容包含到生成的 C 文件中。所以你不需要 #include "y.tab.h",而且,它可能是你大部分错误的原因,因为它被包含得太早了。问题是 ASTNode 是(我假设)在 asttree.h 中定义的,并且从上面的代码片段可以清楚地看出,在处理 y.tab.hasttree.h 尚未包含在内。那行不通,因为语义类型是在 y.tab.h 中声明的;声明将类似于:

union YYSTYPE
{
    int intv;
    char *string;
    ASTnode *node;
    enum OPERATORS op;
};

这要求 ASTnode 已经声明。但事实并非如此,所以我很确定这会产生错误,即使你不记得使用 -Wall 进行编译(你应该这样做;Bison 不会生成生成警告的代码) .由于此时尚未声明 [​​=18=] 并且编译器希望能够继续尝试编译,因此必须使 node 成为指向 某物的指针 ;显然,它使用了 int。这意味着稍后当您尝试使用一个类型假定为 ASTnode* 的变量时,编译器会将该变量视为 int*,当然这使得无法引用该成员该变量指向的对象,因为 int 不是联合或结构,如错误消息所述。此外,您不能将(假定的)int* 分配给 prog,因为(我猜)prog 是在 ASTnode 声明的程序的一部分中声明的是可见的,所以它实际上是一个指向 ASTnode.

的指针

当您从编译中收到大量错误消息时,从一开始就开始修复通常是个好主意;在某些时候,编译器的错误恢复将开始变得无用,之后的错误消息可能只是人为因素。当您尝试在自己的编译器中实现错误恢复时,您很快就会看到它是如何工作的。

最重要的是,您应该从解析器文件中删除 #include "y.tab.h"。它只在词法分析器中需要。我怀疑这是否是唯一的错误,但它可能会帮助您推进项目。