سؤال

OK, I'm doing a few experiments with Lex/Bison(Yacc), and given that my C skills are rather rusty (I've once created compilers and stuff with all these tools and now I'm lost in the first few lines... :-S), I need your help.

This is what my Parser looks like :

%{
#include <stdio.h>
#include <string.h>

void yyerror(const char *str)
{
    fprintf(stderr,"error: %s\n",str);
}

int yywrap()
{
    return 1;
} 

main()
{
    yyparse();
} 

%}

%union 
{
    char* str;
}

%token <str> WHAT IS FIND GET SHOW WITH POSS OF NUMBER WORD

%type <str> statement
%start statements
%%

statement
    : GET { printf("get\n"); }
    | SHOW  { printf("%s\n",$1); }
    | OF { printf("of\n"); }
    ;

statements
    : statement
    | statements statement
    ;

The Issue :

So, basically, whenever the parser comes across a "get", it prints "get". And so on.

However, when trying to print "show" (using the $1 specifier) it gives out a segmentation fault error.

What am I doing wrong?

هل كانت مفيدة؟

المحلول 3

OK, so here's the answer (Can somebody tell me what it is that I always come up with the solution once I've already published a question here in SO? lol!)

The problem was not with the parser itself, but actually with the Lexer.

The thing is : when you tell it to { printf("%s\n",$1); }, we actually tell it to print yylval (which is by default an int, not a string).

So, the trick is to convert the appropriate tokens into strings.

Here's my (updated) Lexer file :

%{
#include <stdio.h>
#include "parser.tab.h"

void toStr();
%}

DIGIT               [0-9]
LETTER              [a-zA-Z]
LETTER_OR_SPACE     [a-zA-Z ]

%%

find    { toStr(); return FIND; }
get     { toStr(); return GET; }
show    { toStr(); return SHOW; }

{DIGIT}+(\.{DIGIT}+)?   { toStr(); return NUMBER; }
{LETTER}+               { toStr(); return WORD; }
\n                      /* ignore end of line */;
[ \t]+                  /* ignore whitespace */;
%%

void toStr()
{
    yylval.str=strdup(yytext);
}

نصائح أخرى

Lex returns a number representing the token, you need to access yytext to get the text of what is parsed.

something like

statement               : GET { printf("get\n"); }
                        | SHOW  { printf("%s\n",yytext); }
                        | OF { printf("of\n"); }
                        ;

to propogate the text of terminals, I go ahead associate a nonterminal with a terminal and pass back the char* and start building the parse tree for example. Note I've left out the type decl and the implementation of create_sww_ASTNode(char*,char*,char*); However, importantly not all nonterminals will return the same type, for number is an integer, word return char* sww return astNode (or whatever generic abstract syntax tree structure you come up with). Usually beyond the nonterminal representing terminals, it's all AST stuff.

sww                     : show word word
                        {
                           $$ = create_sww_ASTNode($1,$2,$3);
                        }
                        ;

word                    : WORD
                        { 
                          $$ = malloc(strlen(yytext) + 1);
                          strcpy($$,yytext);
                        }
                        ;

show                    : SHOW
                        { 
                          $$ = malloc(strlen(yytext) + 1);
                          strcpy($$,yytext);
                        }
                        ;

number                  : NUMBER
                        { 
                           $$ = atoi(yytext);
                        }
                        ;

You don't show your lexer code, but the problem is probably that you never set yylval to anything, so when you access $1 in the parser, it contains garbage and you get a crash. Your lexer actions need to set yylval.str to something so it will be valid:

"show"   { yylval.str = "SHOW"; return SHOW }
[a-z]+   { yylval.str = strdup(yytext); return WORD; }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top