help-bison
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Bison yyparse return array of values


From: Martin Alexander Neumann
Subject: Re: Bison yyparse return array of values
Date: Sun, 2 Apr 2017 16:30:15 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.8.0

Hi Laura,

if you want multiple different parsers (i.e. different .y files) in one
binary, use renaming. See the "%name-prefix"-Option.

In this case, I guess you could stick with globals to store the parsing
result.

If you want to use multiple instances of the same parser simultaneously,
turn the parser into a reentrant one. See the "%define api.pure
full"-Option.

In this case, I would add a function parameter to yyparse() to hand back
the parsing result.

The following example generates a reentrant parser (with renamed prefix)
that stores the linked list of parsed words in a new function parameter
to yyparse() and counts the number of parsed WORDS after yyparse() has
finished.

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

    typedef struct elem {
        char *val;
        struct elem *next;
    } elem_t;

    elem_t *add_word(elem_t *words, char *val) {
        elem_t *word = (elem_t *)malloc(sizeof(elem_t));
        if (word == NULL) {
            fprintf (stderr, "%s", "malloc failed");
            exit(1); }
        word->val = val;
        word->next = words;
        return word;
    }
%}

%output  "parser.c"
%defines "parser.h"

%name-prefix "yy1"
%define api.pure full
%parse-param { elem_t **words };

%union {
    char *str;
}

%token <str> WORD

%start Input

%%

Input
    : WORD          { *words = add_word(NULL, $1);
                      printf("word: %s\n", yylval.str); }
    | Input WORD    { *words = add_word(*words, $2);
                      printf("word: %s\n", yylval.str); }
    ;

%%

int main() {
    elem_t *words = NULL;
    yy1parse(&words);

    int i = 0;
    while (words != NULL) {
        i++;
        words = words->next;
    }

    fprintf(stdout, "Parsed %d WORDS\n", i);
}

void yy1error(char *error) {
    fprintf(stderr, "%s", error);
}

int yy1lex(YYSTYPE *lvalp) {
    static int i = 0;
    while (i++ < 100) {
        lvalp->str = "testWord";
        return WORD;
    }

    return 0;
}
================

Yours, Alex

On 04/02/2017 03:21 PM, Laura Morales wrote:
> Thanks a lot Alex, this works great.
> There is one more thing that I'd like to do. I'd like to have multiple 
> parsers available in the same codebase, such that I can invoke parser1() or 
> parser2() or parser-n(), and in turn get some data structure back depending 
> on the parser I called. Just as an example, let's say I want two parser: one 
> that returns an array of numbers (ignoring all other tokens), and another one 
> that only returns words (ignoring all other tokens). This soon gets messy 
> with global variables.
> I've read in the documentation about the "prefix" option that allows me to 
> replace the "yy" namespace with something else, but if I understand correctly 
> there's another better option available: pure/reentrant parsers. This I 
> suppose, would get rid of globals, although I don't fully understand how this 
> "pure/reentrant" option work.
> My question thus is how can I include multiple parsers together (in the same 
> program) while avoiding globals and also avoiding to turn my code into 
> spaghetti code?
> 
> Thanks once more.
> 
> ========================================================
> 
> Hi Laura,
> 
> I would start with a global linked list that is filled in the semantic
> actions. Building on your example:
> 
> ================
> %{
> #include <stdio.h>
> #include <stdlib.h>
> 
> typedef struct elem {
> char *val;
> struct elem *next;
> } elem_t;
> 
> elem_t *words = NULL;
> 
> void add_word(char *val) {
> elem_t *word = (elem_t *)malloc(sizeof(elem_t));
> if (word == NULL) {
> fprintf (stderr, "%s", "malloc failed");
> exit(1); }
> word->val = val;
> word->next = words;
> words = word;
> }
> %}
> 
> %output "parser.c"
> %defines "parser.h"
> 
> %union { char *str; }
> 
> %token <str> WORD
> 
> %start Input
> 
> %%
> 
> Input
> : WORD { add_word(yylval.str);
> printf("word: %s\n", yylval.str); }
> | Input WORD { add_word(yylval.str);
> printf("word: %s\n", yylval.str); }
> ;
> 
> %%
> ================
> 
> Yours, Alex
> 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]