我有%union{ nodeType *node; }
在解析器。y,但
1。当我调用$num->op或$num->string或$num->nodeType时,发生错误。
。
parser.y:393:28: error: request for member 'op' in something not a structure or union
393 | addop : ADDOP{ $$->op = OP_ADD; }
parser.y:372:36: error: request for member 'string' in something not a structure or union
372 | strcpy(str, $1->string);
parser.y:292:21: error: request for member 'nodeType' in something not a structure or union
292 | $$->nodeType = NODE_VAR_OR_PROC;
2。当我调用newNode或addChild或deleteNode时,出现警告。
。
parser.y:286:22: warning: assignment to 'int *' from incompatible pointer type 'struct nodeType *' [-Wincompatible-pointer-types]
286 | $$ = newNode(NODE_EMPTY);
parser.y:388:24: warning: passing argument 1 of 'addChild' from incompatible pointer type [-Wincompatible-pointer-types]
388 | addChild($$, $2);
| ~~~~~~^~
| |
| int *
parser.y:383:30: warning: passing argument 1 of 'deleteNode' from incompatible pointer type [-Wincompatible-pointer-types]
383 | deleteNode($1);
| ~~~~ ^
| |
| int *
parser.y:
%{
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "ast.h"
#define YYLTYPE LocType
#define MAX_LINE_LENG 256
extern int line_no, col_no, opt_list;
extern char buffer[MAX_LINE_LENG];
extern FILE *yyin; /* declared by lex */
extern char *yytext; /* declared by lex */
extern int yyleng;
struct nodeType* newOpNode(int op);
extern struct nodeType* ASTRoot;
extern
#ifdef __cplusplus
"C"
#endif
int yylex(void);
static void yyerror(const char *msg);
extern int yylex_destroy(void);
%}
%locations
%union {
int val;
char* text;
double dval;
int op;
nodeType *node;
}
%token <node> some token
%type <node> some type
%%
goal: prog {
//fprintf(stdout, "goal: progn");
ASTRoot = $1; YYACCEPT;
};
declarations : declarations VAR var_list SEMICOLON{
$$ = $1;
addChild($$, $3);
deleteNode($2); deleteNode($4);
}
| %empty{
$$ = newNode(NODE_LIST);
}
;
constant : NUMBER {
$$ = $1;
$$->nodeType = NODE_REAL;
}
| DIGSEQ {
$$ = $1;
$$->nodeType = NODE_INT;
}
;
statement : variable ASSIGNMENT expression{
$$ = newNode(NODE_ASSIGN_STMT);
addChild($$, $1);
addChild($$, $3);
$1->nodeType = NODE_SYM_REF;
deleteNode($2);
}
| procedure_statement{
$$ = $1;
}
| compound_statement{
$$ = $1;
}
| IF expression THEN statement else_statement {
$$ = newNode(NODE_IF);
addChild($$, $2); addChild($$, $4); addChild($$, $5);
deleteNode($1); deleteNode($3);
}
| WHILE expression DO statement{
$$ = newNode(NODE_WHILE);
addChild($$, $2); addChild($$, $4);
deleteNode($1); deleteNode($3);
}
| %empty{
$$ = newNode(NODE_EMPTY);
}
;
variable : IDENTIFIER tail{
$$ = newNode(NODE_VAR);
$$->string = $1->string;
addChild($$, $1); addChild($$, $2);
}
;
procedure_statement : IDENTIFIER{
$$ = $1;
$$->nodeType = NODE_VAR_OR_PROC;
}
| IDENTIFIER LPAREN expression_list RPAREN{
$$ = newNode(NODE_PROC_STMT);
addChild($$, $1); addChild($$, $3);
deleteNode($2); deleteNode($4);
}
;
boolexpression : simple_expression{
$$ = $1;
}
| simple_expression relop simple_expression{
$$ = newOpNode($2->op);
addChild($$, $1); addChild($$, $3);
}
;
simple_expression : term{
$$ = $1;
}
| simple_expression addop term{
$$ = newOpNode($2->op);
addChild($$, $1); addChild($$, $3);
deleteNode($2);
}
;
term : factor{
$$ = $1;
}
| term mulop factor{
$$ = newOpNode($2->op);
addChild($$, $1);
addChild($$, $3);
}
;
factor : IDENTIFIER tail{
$$ = newNode(NODE_SYM_REF);
$$->string = $1->string;
addChild($$, $1); addChild($$, $2);
}
| IDENTIFIER LPAREN expression_list RPAREN{
$$ = newNode(NODE_PROC_STMT);
addChild($$, $1); addChild($$, $3);
deleteNode($2); deleteNode($4);
}
| constant{
$$ = $1;
}
| LITERALSTR{
$$ = newNode(NODE_CHAR);
char *str = malloc(sizeof(char)*50);
strcpy(str, $1->string);
$$->string = str;
}
| LPAREN expression RPAREN{
$$ = $2;
deleteNode($1); deleteNode($3);
}
| NOT factor{
$$ = newNode(NODE_OP);
$$->op = OP_NOT;
addChild($$, $2);
deleteNode($1);
}
| SUBOP factor{
$$ = newNode(NODE_OP);
$$->op = OP_SUB;
addChild($$, $2);
deleteNode($1);
}
;
addop : ADDOP{ $$->op = OP_ADD; }
| SUBOP{ $$->op = OP_SUB; }
;
mulop : MULOP{ $$->op = OP_MUL; }
| DIVOP{ $$->op = OP_DIV; }
;
relop : LTOP{ $$->op = OP_LT; }
| GTOP{ $$->op = OP_GT; }
| EQOP{ $$->op = OP_EQ; }
| LETOP{ $$->op = OP_LE; }
| GETOP{ $$->op = OP_GE; }
| NEQOP{ $$->op = OP_NE; }
;
/* @n return the sturct LocType of "n-th node", ex: @1 return the PROGRAM node's locType
$n return the $$ result you assigned to the rule, ex: $1 */
//prog : PROGRAM {
// root = NULL;
/*
printf("program node is @ line: %d, column: %dn",
@1.first_line, @1.first_column);
yylval.val, yylval.text, yylval.dval to get the data (type defined in %union) you assigned by scanner.
*/
// }
// ;
%%
struct nodeType *ASTRoot;
struct nodeType* newOpNode(int op) {
struct nodeType *node = newNode(NODE_OP);
node->op = op;
return node;
}
void yyerror(const char *msg) {
fprintf(stderr,
"[ERROR] line %4d:%3d %s, Unmatched token: %sn",
line_no, col_no - yyleng, buffer, yytext);
}
int main(int argc, const char *argv[]) {
if(argc > 2)
fprintf( stderr, "Usage: ./parser [filename]n" ), exit(0);
FILE *fp = argc == 1 ? stdin : fopen(argv[1], "r");
if(fp == NULL)
fprintf( stderr, "Open file errorn" ), exit(-1);
yyin = fp;
yyparse();
printASTtree(ASTRoot, 0);
/* if(root){
// do pass here
} */
return 0;
}
scanner.l:
%{
/*
* scanner.l
*
* lex input file for pascal scanner
*
*/
#include <stdio.h>
#include <string.h>
#include "ast.h"
#include "parser.h"
int fileno(FILE *);
#define YY_USER_ACTION
yylloc.first_line = line_no;
yylloc.first_column = col_no;
col_no += yyleng;
#define MAX_LINE_LENG 256
#define LIST strcat(buffer, yytext);
#define LIST_FLUSH do{ if(opt_list) printf("%s", buffer); *buffer = 0; }while(0)
#define LOG(TYPE)
do{ LIST;
if(opt_token)
fprintf(stderr, "token(type:%-10s) on line %4d, %3d : %sn",
#TYPE, line_no, col_no - yyleng, yytext);
} while(0)
#ifdef __cplusplus
extern "C" int yylex(void);
#endif
int opt_list = 1, opt_token = 0;
int line_no = 1, col_no = 1;
char buffer[MAX_LINE_LENG];
struct nodeType* newTokenNode(int tokenType);
%}
%option nounput
%option noinput
DIGIT [0-9]
ID [A-Za-z][A-Za-z0-9_]*[A-Za-z0-9]|[A-Za-z]
PM [+-]
STRING "(\.|[^"\])*"
%x comment
%x comments
PRAGMA_LIST_ON "#"[ ]*"pragma"[ ]*"list"[ ]*"on"
PRAGMA_LIST_OFF "#"[ ]*"pragma"[ ]*"list"[ ]*"off"
PRAGMA_TOKEN_OFF "#"[ ]*"pragma"[ ]*"token"[ ]*"on"
PRAGMA_TOKEN_ON "#"[ ]*"pragma"[ ]*"token"[ ]*"off"
%%
/* v could do something */
{P}{R}{O}{G}{R}{A}{M} {yylval.node = newTokenNode(PROGRAM); LOG(KEYWORD); return(PROGRAM); }
"(" {yylval.node = newTokenNode(LPAREN); LOG(KEYWORD); return(LPAREN); }
")" {yylval.node = newTokenNode(RPAREN); LOG(KEYWORD); return(RPAREN); }
";" {yylval.node = newTokenNode(SEMICOLON); LOG(KEYWORD); return(SEMICOLON); }
"." {yylval.node = newTokenNode(DOT); LOG(KEYWORD); return(DOT); }
"," {yylval.node = newTokenNode(COMMA); LOG(KEYWORD); return(COMMA); }
":" {yylval.node = newTokenNode(COLON); LOG(KEYWORD); return(COLON); }
"[" {yylval.node = newTokenNode(LBRACE); LOG(KEYWORD); return(LBRACE); }
"]" {yylval.node = newTokenNode(RBRACE); LOG(KEYWORD); return(RBRACE); }
".." {yylval.node = newTokenNode(DOTDOT); LOG(KEYWORD); return(DOTDOT); }
":=" {yylval.node = newTokenNode(ASSIGNMENT); LOG(KEYWORD); return(ASSIGNMENT); }
"+" {yylval.node = newTokenNode(PLUS); LOG(KEYWORD); return(ADDOP); }
"-" {yylval.node = newTokenNode(MINUS); LOG(KEYWORD); return(SUBOP); }
"*" {yylval.node = newTokenNode(STAR); LOG(KEYWORD); return(MULOP); }
"/" {yylval.node = newTokenNode(SLASH); LOG(KEYWORD); return(DIVOP); }
">" {yylval.node = newTokenNode(GT); LOG(KEYWORD); return(GTOP); }
"<" {yylval.node = newTokenNode(LT); LOG(KEYWORD); return(LTOP); }
"=" {yylval.node = newTokenNode(EQUAL); LOG(KEYWORD); return(EQOP); }
">=" {yylval.node = newTokenNode(GE); LOG(KEYWORD); return(GETOP); }
"<=" {yylval.node = newTokenNode(LE); LOG(KEYWORD); return(LETOP); }
"!=" {yylval.node = newTokenNode(notEQUAL); LOG(KEYWORD); return(NEQOP); }
/* define identifier here */
{ID} {yylval.node = newTokenNode(IDENTIFIER); yylval.node->string = (char*) malloc(yyleng+1); strcpy(yylval.node->string, yytext); LOG(IDENTIFIER); return(IDENTIFIER);}
/* define INTEGERNUM, REALNUMBER, SCIENTIFIC here */
{DIGIT}+ {yylval.node = newTokenNode(DIGSEQ); yylval.node->valueValid = VALUE_I_VALID; yylval.node->iValue = atoi(yytext); LOG(NUMBER); return(DIGSEQ);}
{DIGIT}+"."{DIGIT}+ {yylval.node = newTokenNode(NUMBER); yylval.node->valueValid = VALUE_R_VALID; yylval.node->rValue=atof(yytext); LOG(NUMBER); return(NUMBER);}
{DIGIT}+{E}{PM}?{DIGIT}+ {yylval.node = newTokenNode(NUMBER); yylval.node->valueValid = VALUE_R_VALID; yylval.node->rValue=atof(yytext); LOG(NUMBER); return(NUMBER);}
{DIGIT}+"."{DIGIT}+{E}{PM}?{DIGIT}+ {yylval.node = newTokenNode(NUMBER); yylval.node->valueValid = VALUE_R_VALID; yylval.node->rValue=atof(yytext); LOG(NUMBER); return(NUMBER);}
/* define single/multiple line comment here */
"//" {LIST;BEGIN(comment); if(opt_token) fprintf(stderr, "[INFO ] line %4d:%3d comment stringn", line_no, col_no - yyleng);}
<comment>. LIST;
<comment>n {LIST;LIST_FLUSH;BEGIN(INITIAL);line_no++, col_no = 1;}
"/*" {LIST;BEGIN(comments); if(opt_token) fprintf(stderr, "[INFO ] line %4d:%3d comment string startn", line_no, col_no - yyleng);}
<comments>. LIST;
<comments>n {LIST;LIST_FLUSH;line_no++, col_no = 1;}
<comments>"*/" {LIST;BEGIN(INITIAL); if(opt_token) fprintf(stderr, "[INFO ] line %4d:%3d comment string endn", line_no, col_no - yyleng);}
/* define string constant (LITERALSTR) here */
{STRING} {yylval.node = newTokenNode(CHARACTER_STRING); yylval.node->string = yytext; LOG(LITERALSTR); return(LITERALSTR);}
/*
yylval.text = strdup, strndup ... (yytext)
yylval.dval = atoi, atof, strtod, strtol ... (yytext)
*/
[ tfr] LIST;
n {
LIST;
LIST_FLUSH;
line_no++, col_no = 1;
}
. { LIST; fprintf(stderr, "[ERROR] line %4d:%3d lexical analyzer error %sn", line_no, col_no - yyleng, yytext); }
%%
struct nodeType* newTokenNode(int tokenType) {
struct nodeType *node = newNode(NODE_TOKEN);
node->tokenType = tokenType;
return node;
}
ast.h:
#ifndef __AST_H__
#define __AST_H__
#include "loc.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
/* It's just for reference,
* you can design your own
* struct or class to impl inheritance in c/cpp */
#define VALUE_INVALID 0
#define VALUE_I_VALID 1
#define VALUE_R_VALID 2
#define NODE_TOKEN 1
#define NODE_OP 2
#define NODE_INT 3
#define NODE_REAL 4
more define ...
struct nodeType{
int nodeType;
LocType loc;
/* some fields */
struct nodeType *parent;
struct nodeType *child;
struct nodeType *lsibling;
struct nodeType *rsibling;
/* Attribute for NODE_TOKEN */
int tokenType;
int iValue;
double rValue;
char valueValid;
char *string;
int op;
enum StdType valueType;
struct SymTableEntry *entry;
int defined;
};
struct nodeType* newNode(int type) {
struct nodeType *node = (struct nodeType*)malloc(sizeof(struct nodeType));
node->nodeType = type;
node->valueValid = VALUE_INVALID;
node->string = NULL;
node->parent = NULL;
node->child = NULL;
node->lsibling = node;
node->rsibling = node;
node->defined = 0; // 0: undefiend, 1: defined, 2: parameter
return node;
};
void addChild(struct nodeType *node, struct nodeType *child) {
child->parent = node;
if(node->child == NULL) {
node->child = child;
}
else {
child->lsibling = node->child->lsibling;
child->rsibling = node->child;
node->child->lsibling->rsibling = child;
node->child->lsibling = child;
}
}
void deleteNode(struct nodeType *node) {
if(node->string != NULL)
free(node->string);
free(node);
}
void printASTtree(struct nodeType *node, int ident) {
static char blank[1024];
for(int i=0; i<ident; i++)
blank[i] = ' ';
blank[ident] = 0;
switch(node->nodeType) {
case NODE_TOKEN: printf("%sToken %sn", blank, node->string); break;
case NODE_OP:
switch(node->op) {
case OP_ADD: printf("%s+n", blank); break;
case OP_SUB: printf("%s-n", blank); break;
case OP_MUL: printf("%s*n", blank); break;
case OP_DIV: printf("%s/n", blank); break;
case OP_GT: printf("%s>n", blank); break;
case OP_LT: printf("%s<n", blank); break;
case OP_EQ: printf("%s=n", blank); break;
case OP_GE: printf("%s>=n", blank); break;
case OP_LE: printf("%s<=n", blank); break;
case OP_NE: printf("%s!=n", blank); break;
case OP_NOT: printf("%sNOTn", blank); break;
}
ident++; break;
case NODE_INT: printf("%s%dn", blank, node->iValue); break;
case NODE_REAL: printf("%s%fn", blank, node->rValue); break;
case NODE_CHAR: printf("%s%sn", blank, node->string); break;
case NODE_VAR_OR_PROC: printf("%s%sn", blank, node->string); break;
case NODE_LIST: break;
case NODE_PROGRAM: printf("%s--PROGRAM--n", blank); ident++; break;
case NODE_FUNCTION: printf("%s--FUNCTION--n", blank); ident++; break;
case NODE_PROCEDURE: printf("%s--PROCEDURE--n", blank); ident++; break;
case NODE_VAR_DECL: printf("%sVAR_DECLn", blank); ident++; break;
case NODE_TYPE_INT: printf("%sTYPE_INTn", blank); break;
case NODE_TYPE_ARRAY: printf("%sTYPE_ARRAYn", blank); break;
case NODE_TYPE_REAL: printf("%sTYPE_REALn", blank); break;
case NODE_TYPE_CHAR: printf("%sTYPE_STRINGn", blank); break;
case NODE_ASSIGN_STMT: printf("%sASSIGN_STMTn", blank); ident++; break;
case NODE_SYM_REF: printf("%sSYM_REF %sn", blank, node->string); break;
case NODE_IF: printf("%sIFn", blank); ident++; break;
case NODE_ELSE: printf("%sELSEn", blank); ident++; break;
case NODE_WHILE: printf("%sWHILEn", blank); ident++; break;
case NODE_FOR: printf("%sFORn", blank); ident++; break;
case NODE_REPEAT: printf("%sREPEATn", blank); ident++; break;
case NODE_WITH: printf("%sWITHn", blank); ident++; break;
case NODE_GOTO: printf("%sGOTOn", blank); ident++; break;
case NODE_LABEL_DECL: printf("%sLABEL_DECLn", blank); ident++; break;
case NODE_LABEL: printf("%sLABEL %dn", blank, node->iValue); break;
}
struct nodeType *child = node->child;
if(child != NULL) {
do {
printASTtree(child, ident);
child = child->rsibling;
} while(child != node->child);
}
}
#define Obj void*
typedef struct ConsTag{
Obj car;
struct ConsTag *cdr;
} *Cons, ConsStr;
#endif
我有%union{nodeType *node;} in parser.y
你确实有。但是我在代码转储中没有看到你告诉编译器nodeType
是什么。很有可能是编译器抱怨了这个问题,而您没有费心在问题中包含相关的错误或警告。也有可能你确实在某个地方做了typedef ... nodeType
,也许是用错误的定义,在你没有显示的代码部分,因为尽管你已经在你的问题中倾倒了大约一千行代码,它仍然不能成为一个可复制的例子,这是我们要求你提供的。(这远不是最小的,但这是另一个问题。)
我很确定你的实际代码不包括:
%type <node> some type
它确实声明一些或所有非终结符具有类型标记node
似乎是合理的,尽管最好包含实际的Bison声明,因为这将更接近于使编译代码成为可能。因此,可能是您实际上没有正确地指定非终结符的标签,其缩减操作正在生成这些错误。但是您的标记似乎都没有类型int*
,所以除非您从%union
声明中省略了一些标记,否则我怀疑这是不正确的%type
声明的结果,并且Bison没有未声明的非终结符的默认类型。(或者,更准确地说,默认值是"无语义值",这会产生不同的警告。)
因此,根据现有证据,最合理的猜测是编译器看到nodeType
没有声明为类型,并且为了继续编译替换int
;这将使node
联合成员为int*
,这与错误一致。但这只是猜测。如果发生了这种情况,应该在早期的错误消息中有一些指示。
虽然我不认为这是相关的,我注意到你这样做:
struct nodeType{
int nodeType;
// ...
这是完全合法的,根据C标准:struct
标签在他们自己的命名空间中,只与union
和enum
标签共享。即使使用typedef struct nodeType nodeType
将nodeType
引入全局名称空间也是合法的,尽管这似乎不是您首选的样式。但是对于类型(或struct
标签)和变量(或struct
成员)使用相同的标识符仍然令人困惑。