我正在开发一个涉及编译器或解释器的抽象语法树 (AST) 结构的 C 项目。该项目旨在解析编程语言并生成代码的 AST 表示形式以供进一步处理。 我在我的项目中引入了一个名为 _prog_tree 的新结构,旨在表示 AST 中的程序(我必须遵循给定的语法)。该结构包括命令字段和程序字段,分别由 AST_comm 和 AST_prog 表示。 这是相关代码片段
struct _prog_tree {
AST_comm commande;
AST_prog programme;
};
typedef struct _prog_tree* AST_prog;
但是,在将这个结构体和 typedef 添加到我的项目中时,我遇到了编译错误,表明 AST_comm 和 AST_prog 是未知类型。奇怪的是,当我如下修改 typedef 时:
typedef struct _prog_tree* AST_prog;
编译错误消失了,但我在运行时遇到分段错误,特别是在词法分析器创建前六个标记之后。
这是 parser.y 文件:
/* file parseur.y
* compilation: bison -d parseur.y
* result: parseur.tab.c = C code for syntaxic analyser
* result: parseur.tab.h = def. of lexical units aka lexems
*/
%{ // the code between %{ and %} is copied at the start of the generated .c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "AST.h"
int yylex(void); // -Wall : avoid implicit call
int yyerror(AST_comm**,int*, const char*); // on fonctions defined by the generator
int i = 1;
%}
%parse-param {AST_comm **rez} {int *size}
%union {AST_comm tree;
AST_expr leaf;
double number;
bool boolean;
char* string}
%token <number> NUMBER
%token ELSE
%token IF
%token WHILE
%type <leaf> expression
%type <tree> program
%type <tree> commande
%token <boolean> BOOLEAN
%token <string> IDENT
%start program
%right '='
%left EQ LEQ REQ NEQ '>' '<' AND
%left '+' '-'
%left '*' '/'
%nonassoc UMOINS '!' IMPORT
%%
program :
{
}
| commande program
;
commande: expression ';'
{
if (*rez == NULL) {
*rez = (AST_comm*)malloc(sizeof(AST_comm));
} else {
AST_comm *tmp = (AST_comm*)realloc(*rez, sizeof(AST_comm) * i);
if (tmp == NULL) {
free(*rez);
return 0;
}
*rez = tmp;
}
if (*rez == NULL) {
return 0; // Allocation failed
}
(*rez)[i-1] = new_command($1, NULL, NULL, NULL);
*size = ++i;
}
| IMPORT IDENT ';'
{
/*Ajouter lecture de fichier au niveau de code_gen*/
}
| '{' program '}'
{
$$ = $2;
}
| WHILE '(' expression ')' commande
{
$$ = new_command(NULL, NULL, NULL, NULL);
$$->rule = 'W';
$$->expr1 = $3;
$$->com1 = $5;
}
|IF '(' expression ')' commande ELSE commande
{
$$ = new_command(NULL, NULL, NULL, NULL);
$$->rule = 'Z';
$$->expr1 = $3;
$$->com1 = $5;
$$->com2 = $7;
}
;
expression:
expression '+' expression
{$$ = new_binary_expr('+',$1,$3, NULL);}
| expression '-' expression
{$$ = new_binary_expr('-',$1,$3, NULL);}
| expression '*' expression
{$$ = new_binary_expr('*',$1,$3, NULL);}
| expression '/' expression
{$$ = new_binary_expr('/',$1,$3, NULL);}
| expression EQ expression
{$$ = new_binary_expr('=',$1,$3, NULL);}
| expression LEQ expression
{$$ = new_binary_expr('L',$1,$3, NULL);}
| expression REQ expression
{$$ = new_binary_expr('R',$1,$3, NULL);}
| expression NEQ expression
{$$ = new_binary_expr('E',$1,$3, NULL);}
| expression '<' expression
{$$ = new_binary_expr('<',$1,$3, NULL);}
| expression '>' expression
{$$ = new_binary_expr('>',$1,$3, NULL);}
| expression AND expression
{$$ = new_binary_expr('&',$1,$3, NULL);}
| '!' expression
{$$ = new_unary_expr('!',$2, NULL);}
| '(' expression ')'
{$$ = $2;}
| '-' expression %prec UMOINS
{$$ = new_unary_expr('M',$2, NULL);}
| IDENT '=' expression
{$$ = new_unary_expr('A',$3, $1);}//Pour le moment je fais binaire mais il faut faire unary
| NUMBER
{$$ = new_number_expr($1);}
| BOOLEAN
{$$ = new_bool_expr($1);}
| IDENT
{$$ = new_str_expr($1);}
;
%% // denotes the end of the grammar
// everything after %% is copied at the end of the generated .c
int yyerror(AST_comm **rez, int *size, const char *msg){ // called by the parser if the parsing fails
printf("Parsing:: syntax error in \n");
return 1; // to distinguish with the 0 retured by the success
}
这是 lexer.l 文件:
/* file lexeur.l
* compilation: flex lexeur.l
* result: lex.yy.c = lexical analyser in C
*/
%{
#include <stdio.h> // printf
#include <stdbool.h> //bool
#include "AST.h"
#include "parser.tab.h" // token constants defined in parseur.y via #define
%}
SCI [0-9]+.[0-9]*[\e\E][\-\+]?[0-9]+|\.[0-9]+[\e\E][\-\+]?[0-9]+|[0-9]+[\e\E][\-\+]?[0-9]+
%%
[0-9]+\.[0-9]*|\.[0-9]+|[0-9]+ {printf("lex: création token NUMBER %s\n",yytext);yylval.number=atof(yytext);
return NUMBER; }
{SCI} {printf("lex: création token NUMBER sci %s\n",yytext);yylval.number=atof(yytext);
return NUMBER; }
NaN {printf("lex: création token NUMBER NaN\n");yylval.number=0.0 / 0.0;
return NUMBER;}
True {printf("lex: création token BOOLEAN %s\n",yytext); yylval.boolean=true;
return BOOLEAN; }
False {printf("lex: création token BOOLEAN %s\n",yytext); yylval.boolean=false;
return BOOLEAN; }
"if" { printf("lex: création token IF\n"); return IF; }
else { printf("lex: création token ELSE\n"); return ELSE; }
while { printf("lex: création token WHILE\n"); return WHILE; }
"//"([a-z]|[0-9]|[A-Z]|[ ])*[\n] { ; }
"/*"([a-z]|[0-9]|[A-Z]|[ \n])*"*/" { ; }
import {printf("lex: création token %s\n",yytext); return IMPORT;}
[a-z]([a-z]|[0-9]|[A-Z]|[_])* {printf("lex: création token IDENT %s\n",yytext); yylval.string = strdup(yytext);
return IDENT; }
[ \t\r] { ; }
\n {printf("lex: fin de lecture");
return 0;}
"==" {printf("lex: création token %s\n",yytext); return EQ;}
"<=" {printf("lex: création token %s\n",yytext); return LEQ;}
">=" {printf("lex: création token %s\n",yytext); return REQ;}
"!=" {printf("lex: création token %s\n",yytext); return NEQ;}
"&&" {printf("lex: création token %s\n",yytext); return AND;}
. {printf("lex: création token %s\n",yytext); return yytext[0];}
%%
int yywrap(void){ return 1; } // function called at the end of the file
我正在寻求帮助以了解为什么会出现这些问题以及如何解决这些问题。该问题是否与错误包含标头、结构声明或 typedef 有关?任何解决此问题的见解或建议将不胜感激。谢谢!
当你有:
struct _prog_tree {
AST_comm commande;
AST_prog programme;
};
typedef struct _prog_tree* AST_prog;
在使用后才定义名称
AST_prog
,这是行不通的。
修复方法很简单:
typedef struct _prog_tree* AST_prog;
struct _prog_tree {
AST_comm commande;
AST_prog programme;
};
这将
AST_prog
声明为 struct _prog_tree *
的别名。
您应该考虑 typedef 指针是一个好主意吗? 中的讨论 - 简短的答案通常是“否”。
此外,一般情况下,您不应创建以下划线开头的函数、变量、标签或宏名称。 C11 §7.1.3 保留标识符的一部分说:
- 所有以下划线开头的标识符以及大写字母或其他下划线始终保留供任何使用。
- 所有以下划线开头的标识符始终保留用作普通名称空间和标记名称空间中文件范围的标识符。
另请参阅 双下划线 (
__const
) 在 C 中意味着什么?