我正在尝试打印AST并在树中打印标识符的实际名称。 我正在使用lex和yacc。
出于某种原因,yacc在一行中读取所有令牌,直到&#39 ;;'这使我无法使用yytext访问标识符的文本值。
这是lex文件:
%{
%}
%%
"&&" {return OP_AND;}
\"|"\"|" {return OP_OR;}
!= {return OP_NE;}
== {return OP_EQ;}
> {return OP_GT;}
>= {return OP_GE;}
\< {return OP_LT;}
\<= {return OP_LE;}
! {return OP_NOT;}
= {return ASSIGN;}
\+ {return PLUS;}
\- {return MINUS;}
\* {return MULT;}
\/ {return DIV;}
\& {return ADRS;}
\^ {return PTR_VAL;}
\; {return SEMI;}
, {return COMMA;}
\{ {return CURLY_O;}
\} {return CURLY_C;}
\( {return PAREN_O;}
\) {return PAREN_C;}
\| {return BAR;}
\[ {return SQR_O;}
\] {return SQR_C;}
else {return ELSE;}
if {return IF;}
do {return DO;}
for {return FOR;}
bool {return BOOL;}
void {return VOID;}
int { return INT;}
charp {return CHARP;}
intp {return INTP;}
string {return STRING;}
while {return WHILE;}
true {return TRUE_;}
false {return FALSE_;}
return {return RETURN;}
null {return NULL_;}
0|[1-9][0-9]* {return CONST_INT;}
[a-zA-Z][a-zA-Z0-9]* { return IDENT;}
\'.\' {return CONST_CHAR; }
\".*\" {return CONST_STRING; }
\[\$([^\$]*\$+[^\]])*[^\$]*\$+\] { /*comment*/}
[ \n\t] { /* skip whitespace */}
. {return ILLEAGAL;}
%%
这是yacc文件: *请注意,某些规则尚未完全准备好但未被此输入文件使用,并且与此案例无关。
%{
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
extern char * yytext;
typedef struct node
{
char * token;
struct node *b1;
struct node *b2;
struct node *b3;
struct node *b4;
}node;
int yylex();
int yyerror();
struct node* mknode2(char* token,node* b1,node* b2);
struct node* mknode3(char* token,node*b1,node*b2,node*b3);
struct node* mknode4(char* token,node*b1,node*b2,node*b3,node*b4);
int printtree(node* tree);
#define YYSTYPE node*
%}
%token SEMI COMMA CURLY_O CURLY_C PAREN_O PAREN_C SQR_O SQR_C BAR
%token BOOL INT CHAR STRING INTP CHARP VOID
%token IF DO WHILE FOR RETURN
%token CONST_INT CONST_CHAR CONST_STRING NULL_ IDENT TRUE_ FALSE_
%token ILLEAGAL
%right ASSIGN
%left OP_OR OP_AND OP_NE OP_EQ OP_GT OP_GE OP_LT OP_LE
%left PLUS MINUS
%left MULT DIV
%right OP_NOT
%right ADRS
%right PTR_VAL
%nonassoc LOWER_THAN_ELSE
%nonassoc ELSE
%start program
%%
program : functions {printtree($1);}
;
functions : functions function {$$ = mknode2("FUNC" ,$2,$1);}
| {$$ = NULL;}
;
function : type id PAREN_O f_params PAREN_C CURLY_O body CURLY_C { $$ = mknode3($1,$2,$4,$7);}
;
body : var_decls stmts ret_stmt {$$ = mknode3("BODY" ,$1 , $2 , $3);}
;
nest_block : stmts {$$=$1;}
;
f_params : f_params_ {$$ = $1;}
| {$$ = NULL;}
;
f_params_ : f_params_ COMMA param {$$ = mknode2("," , $3 , $1);}
| param {$$ = $1;}
;
param : type id {$$ = mknode2($1 , NULL , $2 );}
;
var_decls : var_decls var_decl { $$ = mknode2("DECL" , $2 , $1);}
| var_decls function {$$ = mknode2("DECL" , $2 , $1);}
| {$$ = NULL;}
;
var_decl : type var_list SEMI { $$ = mknode2($1 , NULL , $2); }
;
var_list : var_list COMMA dec_assign {$$ = mknode2(",", $3 , $1);}
| dec_assign { $$ = $1 ;}
;
dec_assign : id ASSIGN expr { $$ = mknode2("=", $1 , $3);}
| id {$$ = $1; }
;
type : BOOL {$$ = yytexy;}
| INT { $$ = yytext;}
| CHAR {$$ = yytext;}
| INTP {$$ = yytext;}
| CHARP {$$ = yytext;}
| STRING {$$ = yytext;}
| VOID {$$ = yytext;}
;
stmts : stmts stmt { $$ = mknode2("STMT" , $2 , $1 );}
| { $$ = NULL ;}
;
stmt : assignment SEMI {$$ = $1 ;}
| fct_call SEMI {$$ = $1; }
| IF PAREN_O expr PAREN_C opt_nest %prec LOWER_THAN_ELSE {$$ = mknode2("if" , $3 , $5 );}
| IF PAREN_O expr PAREN_C opt_nest ELSE opt_nest {$$ = mknode3("if" , $3 , $5 , $7 );}
| WHILE PAREN_O expr PAREN_C opt_nest {$$ = mknode2("while" , $3 , $5);}
| DO CURLY_O nest_block CURLY_C WHILE PAREN_O expr PAREN_C SEMI {$$ = mknode2("do" , $3 , $7);}
| FOR PAREN_O assignment SEMI expr SEMI assignment PAREN_C opt_nest {$$ = mknode4("for" , $3 , $5 , $7 , $9 );}
;
opt_nest : CURLY_O nest_block CURLY_C {$$ = $2;}
| stmt {$$ = $1;}
;
ret_stmt : RETURN expr SEMI { $$ = mknode2("return" , NULL , $2);}
| { $$ = NULL; }
;
assignment : id ASSIGN expr {$$ = mknode2("=" , $1, $3);}
| id SQR_O expr SQR_C ASSIGN expr {$$ = mknode3("=" , $1 , $3, $6 );}
;
fct_call : id PAREN_O expr_list PAREN_C {$$ = mknode2("FUNCALL" , $1 ,$3 );}
;
expr_list : expr_list_ expr {$$ = mknode2("AGRS" , $2 , $1);}
| {$$ = NULL;}
;
expr_list_ : expr_list_ expr COMMA { $$ = mknode2("," , $2 , $1);}
| {$$ = NULL;}
;
id : IDENT { $$ = mknode2(strdup(yytext) , NULL , NULL);}
;
expr : expr PLUS expr { $$ = mknode2("+" , $1 , $3);}
| expr MINUS expr { $$ = mknode2("-" , $1 , $3);}
| expr MULT expr { $$ = mknode2("*" , $1 , $3);}
| expr DIV expr { $$ = mknode2("/" , $1 , $3);}
| expr OP_AND expr { $$ = mknode2("&&" , $1 , $3);}
| expr OP_OR expr { $$ = mknode2("||" , $1 , $3);}
| expr OP_NE expr { $$ = mknode2("!=" , $1 , $3);}
| expr OP_EQ expr {$$=mknode2("==",$1,$3);}
| expr OP_GT expr {$$=mknode2(">",$1,$3);}
| expr OP_GE expr {$$=mknode2(">=",$1,$3);}
| expr OP_LT expr {$$=mknode2("<",$1,$3);}
| expr OP_LE expr {$$=mknode2("<=",$1,$3);}
| OP_NOT expr {$$=mknode2("!",NULL,$2);}
| PTR_VAL expr {$$=mknode2("^",NULL,$2);}
| ADRS expr {$$=mknode2("&",NULL,$2);}
| MINUS expr {$$=mknode2("-",NULL,$2);}
| literal {$$=mknode2($1,NULL,NULL);}
| fct_call {$$= $1 ;}
| id {$$= $1;}
| PAREN_O expr PAREN_C {$$=mknode2("(_)",NULL,$2);}
| BAR expr BAR {$$=mknode2("|_|",NULL,$2);}
;
literal : CONST_INT {$$ = "const_int";}
| TRUE_ { $$ = "true" ;}
| FALSE_ { $$ = "false" ;}
| CONST_CHAR { $$ = "const_char" ;}
| CONST_STRING { $$ = "const_string" ;}
| NULL_ { $$ = "null" ;}
;
%%
#include "lex.yy.c"
void main(){
return yyparse();
}
int tabCount =0;
struct node* mknode2(char* token,node*b1,node*b2)
{
node* newnode=(node*)malloc(sizeof(node));
char* newstr;
if( token ){
printf("token: %s \n" , token);
newstr=(char*)malloc(sizeof(token)+1);
newstr[sizeof(token)]='\0';
strcpy(newstr,token);
}
else{
newstr=(char*)malloc(3);
strcpy(newstr,"AA");
}
newnode->b1=b1;
newnode->b2=b2;
newnode->b3=NULL;
newnode->b4=NULL;
newnode->token=newstr;
return newnode;
}
struct node* mknode3(char* token,node*b1,node*b2,node*b3)
{
node* newnode= mknode2(token,b1,b2);
newnode->b3=b3;
return newnode;
}
struct node* mknode4(char* token,node*b1,node*b2,node*b3,node*b4)
{
node* newnode= mknode3(token,b1,b2,b3);
newnode->b4=b4;
return newnode;
}
void printTabs(){
int i;
for(i=0;i<tabCount;i++){
printf("\t");
}
}
int printtree(node* tree)
{
tabCount++;
printTabs();
printf("%s\n",tree->token);
if(tree->b1)printtree(tree->b1);
if(tree->b2)printtree(tree->b2);
if(tree->b3)printtree(tree->b3);
if(tree->b4)printtree(tree->b4);
tabCount--;
return 1;
}
int yyerror(){
printf("ERROR!\n");
return 0;
}
这是输入文件:
void main(int x){
int y,w,r; int z;
}
这是预购的输出AST:
FUNC
void
main
int x
x
BODY
DECL
int z;
;
DECL
int y,w,r;
,
;
,
,
,
我预期的输出:
FUNC
void
main
int
x
BODY
DECL
int
z
DECL
int
,
y
,
w
r
当我达到规则时可以看出:输入我的yacc文件yytext包含整个句子(&#34; int y,w,r;&#34;而不仅仅是&#34; int&#34 ;)当我到达规则时:id它只包含一个令牌,恰好是一个令牌转发,然后是预期的令牌。
- 请注意,在函数名称和函数参数中,yytext可以正常工作。
- 我尝试从lex文件中打印yytext,并且标记似乎包含正确的值。
答案 0 :(得分:1)
yytext
指向扫描的最后一个lexeme。任何其他以前保存的指针进入扫描程序的内部缓冲区(例如前一个值yytext
)都是无效的,并且不能假定x指向任何有用的指针。
在解析器操作中,您几乎不知道扫描的最后一个令牌是什么。 Yacc / bison生成LALR(1)解析器,其中1
表示&#34;一个预测标记&#34;。这意味着解析器(可以)始终检查 next 令牌,如果这样做,那么令牌yytext
将指向该令牌。有些实现总是在前面阅读;其他人,比如野牛,如果先行者不会改变解析器的行为,有时候就不会提前读。因此,在解析器操作期间指向哪个令牌yytext
未指定,并且可能在将来的版本或不同的实现中更改。
底线:从不在解析器操作中使用yytext
。并且永远不会将yytext
的指针值从扫描程序传递给解析器。如果您需要解析器中令牌的字符串值,制作字符串的副本并通过yylval
将副本的地址传递给解析器。如果您使用strdup
或类似内容,请在不再需要时忘记free
副本。