Using $x to grab string from rule

余生颓废 提交于 2020-01-06 04:53:09

问题


I'm trying to do something like this in Bison...

loop_for:   FOR var_name COLONEQUALS expression TO
            {printf("%s<=", $2);} expression STEP
            {printf("%s+=", $2);} expression {printf(")\n");}
            Code ENDFOR

What I'm trying to do is convert a for statement from the fake language's syntax to C's. However, the $2 I've used to grab var_name doesn't seem to work as the program crashes when it reaches there. Is $x supposed to work only for integers?

I even tried adding a union and using char* for a new type, but I still get (null) from the above actions.

EDIT:
I tried to fix it using the hints from the questions that were provided, but I still can't get it perfect.

FLEX rules in question:

"FOR"   {printf("for ("); lisnew=0; return FOR;}
"TO"    {printf("; "); return TO;}
"STEP"  {printf("; "); return STEP;}
"ENDFOR"    {printf("\n"); t--; instabs(); printf("}\n"); instabs(); lisnew=1; return ENDFOR;}
[a-zA-Z]+   {printf("%s",yytext); lisnew=0; yylval.strV = yytext; return CHARACTERS;}
":="    {printf("="); lisnew=0; return COLONEQUALS;}

BISON rules:

loop_for:   FOR var_name {strcpy(myvar, $<strV>2);} COLONEQUALS expression TO {printf("%s<=", myvar);} expression STEP {printf("%s+=", myvar);} expression {printf(")\n");} Code ENDFOR
var_name:   name_first_is_char
name_first_is_char: character | character name2
name2:  | character name2 | digit name2

Thing is, for input:

FOR i := 0 TO 10 STEP 1

I get as output:

for ( i = 0 ; i :=<= 10 ; i :=+= 1

Can't I avoid having the := symbols getting in the strV?

EDIT 2:
I tried again, this time with

var_name:   name_first_is_char {memset(myvar, '\0', BUFFER_LENGTH); sprintf(myvar, "%s", $<strV>1);}

But still the next few characters get in myvar.


回答1:


What you need to consider is that yytext is a pointer to a character. That sequence of characters changes all the time in flex, but yytext (the pointer) is constant. Your original flex rule simply sets that pointer in yylval. So when the parser continues, it engulfs the := from input as well. This is why in flex, you should copy the string and store it somewhere as soon as it matches. That somewhere could be a field in yylval union. I always malloc space for all constants and variable names before using them in Bison.




回答2:


I managed to get around working with the Bison's $x by identifying variable names with a regular expression in flex and passing them to a string which is then extern'ed from Bison, and available for use anytime.

So some of the changes made are...

FLEX

char tempvar[1000];
[a-zA-Z][a-zA-Z0-9]*    {printf("%s",yytext); strcpy(tempvar,yytext); lisnew=0; yylval.strV = yytext; return VARNAME;}

BISON

extern char tempvar[];
var_name:    VARNAME {strcpy(myvar, tempvar);}
loop_for:   FOR var_name COLONEQUALS number TO {printf("%s<=", myvar);} number STEP {printf("%s+=", myvar);} number {printf(")\n"); instabs(); printf("{\n"); t++; instabs();} Code ENDFOR

EDIT: With credit due to Jonathan Leffler, this (below) should also work, allowing access via the usual $x in Bison.

Partial code

FLEX

[a-zA-Z][a-zA-Z0-9]*    { yylval = strdup(yytext); return VARNAME;}
[1-9][0-9]*|0           { yylval = strdup(yytext); return NUMBER; }

BISON

loop_for:   FOR var_name COLONEQUALS NUMBER TO NUMBER STEP NUMBER
    { printf("for (%s = %s; %s <= %s; %s += %s)\n", $2, $4, $2, $6, $2, $8); }

Jonathan reports that although this works, it should be used carefully as strdup() used in this manner without free() statements should result in major memory leaks.

See also SO 3539416 for more info.




回答3:


No, the $x notation is not restricted solely to integer values (well, the x has to be an integer, but the value represented by $x does not).

See whether this question helps at all:

  • SO 3344267


来源:https://stackoverflow.com/questions/3539498/using-x-to-grab-string-from-rule

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!