Reputation: 27
I have %union{ nodeType *node; }
in parser.y, but
1.When i call $num->op or $num->string or $num->nodeType, error occurred.
ex.
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.When i call newNode or addChild or deleteNode, warning occurred.
ex.
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 *
%{
#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: prog\n");
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: %d\n",
@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: %s\n",
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 error\n" ), exit(-1);
yyin = fp;
yyparse();
printASTtree(ASTRoot, 0);
/* if(root){
// do pass here
} */
return 0;
}
%{
/*
* 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 : %s\n", \
#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 string\n", 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 start\n", 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 end\n", 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)
*/
[ \t\f\r] LIST;
\n {
LIST;
LIST_FLUSH;
line_no++, col_no = 1;
}
. { LIST; fprintf(stderr, "[ERROR] line %4d:%3d lexical analyzer error %s\n", line_no, col_no - yyleng, yytext); }
%%
struct nodeType* newTokenNode(int tokenType) {
struct nodeType *node = newNode(NODE_TOKEN);
node->tokenType = tokenType;
return node;
}
#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 %s\n", 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("%sNOT\n", blank); break;
}
ident++; break;
case NODE_INT: printf("%s%d\n", blank, node->iValue); break;
case NODE_REAL: printf("%s%f\n", blank, node->rValue); break;
case NODE_CHAR: printf("%s%s\n", blank, node->string); break;
case NODE_VAR_OR_PROC: printf("%s%s\n", 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_DECL\n", blank); ident++; break;
case NODE_TYPE_INT: printf("%sTYPE_INT\n", blank); break;
case NODE_TYPE_ARRAY: printf("%sTYPE_ARRAY\n", blank); break;
case NODE_TYPE_REAL: printf("%sTYPE_REAL\n", blank); break;
case NODE_TYPE_CHAR: printf("%sTYPE_STRING\n", blank); break;
case NODE_ASSIGN_STMT: printf("%sASSIGN_STMT\n", blank); ident++; break;
case NODE_SYM_REF: printf("%sSYM_REF %s\n", blank, node->string); break;
case NODE_IF: printf("%sIF\n", blank); ident++; break;
case NODE_ELSE: printf("%sELSE\n", blank); ident++; break;
case NODE_WHILE: printf("%sWHILE\n", blank); ident++; break;
case NODE_FOR: printf("%sFOR\n", blank); ident++; break;
case NODE_REPEAT: printf("%sREPEAT\n", blank); ident++; break;
case NODE_WITH: printf("%sWITH\n", blank); ident++; break;
case NODE_GOTO: printf("%sGOTO\n", blank); ident++; break;
case NODE_LABEL_DECL: printf("%sLABEL_DECL\n", blank); ident++; break;
case NODE_LABEL: printf("%sLABEL %d\n", 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
Upvotes: 0
Views: 108
Reputation: 241861
I have %union{ nodeType *node; } in parser.y
Indeed you do. But I don't see anywhere in that code dump where you tell the compiler what nodeType
is. It's quite possible that the compiler complained about that, and that you didn't bother to include the relevant error or warning in your question. Or it's possible that you do actually typedef ... nodeType
somewhere, maybe with the wrong definition, in the part of your code which you don't show, because although you've dumped around a thousand lines of code into your question, it still fails to be a reproducible example, which is what we ask you to provide. (And it's far from minimal, but that's another issue.)
I'm pretty sure that your real code does not include:
%type <node> some type
It seems reasonable that it does declare some or all of your non-terminals to have type tag node
, athough it would be better to include the actual Bison declaration since that would come closer to making it possible to try compiling your code. So it could be that you haven't actually correctly specified the tag for the non-terminals whose reduction actions are generating those errors. But none of your tags appear to have type int*
, so unless you've omitted some of the tags from the %union
declaration, I doubt that this is the result of an incorrect %type
declaration, and Bison doesn't have a default type for undeclared non-terminals. (Or, more accurately, the default is "no semantic value", which would produce a different warning.)
So the most plausible guess based on the available evidence is that your compiler sees that nodeType
is not declared as a type, and in order to continue compiling substitutes int
; that would make the node
union member an int*
, which is consistent with the errors. But that's just a guess. If that's what happened, there should be some indication in an earlier error message.
Although I don't think it's related, I note that you do this:
struct nodeType{
int nodeType;
// ...
That's totally legal, according to the C standard: struct
tags are in their own namespace, only shared with union
and enum
tags. It would be legal even if you had introduced nodeType
into the global namespace with typedef struct nodeType nodeType
, although that appears to not be your preferred style. But IMHO it's still confusing to use the same identifier both for a type (or struct
tag) and for a variable (or struct
member).
Upvotes: 1