view gen/y.yy @ 174:0c4e9e76a2f2

all: Make ylisp work in Release mode too by changing the way asserts are used when there are side-effects.
author Lewin Bormann <lbo@spheniscida.de>
date Mon, 09 Sep 2019 19:57:39 +0200
parents 1b2bd8c6cc25
children
line wrap: on
line source

%code requires{
typedef void* yyscan_t;

#include <src/expr.h>
#include <src/value.h>
#include <src/base/str.h>
#include <src/base/vec.h>
}

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

#include <gen/y.tab.h>

bool YENABLE_DEBUG_PRINT = false;

#define ydbg_print(...) if (YENABLE_DEBUG_PRINT) fprintf(stderr, __VA_ARGS__)

// Our error handler
void yyerror(void* ignored, void* ignored2, ystr_t* ystr_error, char const* s);

// Declare flex-generated functions
int yylex(YYSTYPE* v, void* scanner);
int yylex_init (yyscan_t* scanner);
int yylex_destroy ( yyscan_t yyscanner );
void yyset_out  ( FILE * _out_str , yyscan_t yyscanner );
void yyset_in  ( FILE * _in_str , yyscan_t yyscanner );
%}

%define parse.error verbose
%{ // The `scan` parameter is present in yyparse() as first argument and forwarded to yylex() as second argument.
%}
%param {void* scan}

%{ // The output_yexprs parameter is only present in yyparse() as second argument and used in actions.
%}
%parse-param {yvec_t* output_yexprs}

%{ // The ystr_error parameter is only present in yyparse.
%}
%parse-param {ystr_t* ystr_error}

%{ // Supply yylval argument to yylex().
%}
%define api.pure full

%define lr.type ielr

%union yvalue {
// Parsed values ('semantic values'):

// More yexprs.
yvec_t exprs;
// One yexpr.
yexpr_t expr;
// A reference.
yref_t ref;

// Lexed values:

// A number literal (todo: floats)
long long number;
// A string literal.
char* string;
// An atom.
char* atom;
}

%{ // Type of yylval.
%}
%token <number> TOK_NUMBER_LITERAL
%token <string> TOK_STRING_LITERAL
%token <atom> TOK_ATOM
%token TOK_QUOTE
%token TOK_LEFTP
%token TOK_RIGHTP

%type <exprs> many_sexpr
%type <expr> sexpr
%type <expr> literal
%type <expr> inner_sexpr
%type <expr> inner_quoted_sexpr
%type <expr> value
%type <expr> quoted_value

%%

prog: many_sexpr {
            // Assign overall result (list of yexpr_t) to parser's output
            // argument.
            yvec_append(output_yexprs, &$1);
            yvec_destroy(&$1);
            ydbg_print("finished\n");
    }

many_sexpr: many_sexpr sexpr {
            // Push found sexpr to previous sexprs.
            YVEC_PUSH(&$1, &$2);
            // Push result on stack.
            $$ = $1;
    }
    | %empty {
            yvec_t v;
            YVEC_INIT(&v, 0, yexpr_t);
            $$ = v;
    };

sexpr: TOK_QUOTE TOK_LEFTP inner_quoted_sexpr TOK_RIGHTP {
                ydbg_print("found quoted sexpr\n");
                $$ = $3;
    }
    | TOK_LEFTP inner_sexpr TOK_RIGHTP {
                ydbg_print("found sexpr\n");
                $$ = $2;
    };

inner_quoted_sexpr: inner_quoted_sexpr quoted_value {
                  yexpr_init_or_extend(&$1, $2);
                  $$ = $1;
            }
            // A quoted sexpr can contain more sexprs, but they are quoted too.
            | inner_quoted_sexpr TOK_LEFTP inner_quoted_sexpr TOK_RIGHTP {
                  yexpr_init_or_extend(&$1, $3);
                  $$ = $1;
            }
            | %empty {
                  ydbg_print("finished quoted sexpr\n");
                  yexpr_t e = yexpr_new();
                  yvec_t v;
                  YVEC_INIT(&v, 0, yexpr_t);
                  yexpr_set_list(&e, v);
                  $$ = e;
            };

inner_sexpr: inner_sexpr value {
                yexpr_init_or_extend(&$1, $2);
                $$ = $1;
           }
           | inner_sexpr sexpr {
                yexpr_init_or_extend(&$1, $2);
                $$ = $1;
           }
           | %empty {
                ydbg_print("finished sexpr\n");
                yexpr_t e = yexpr_new();
                yvec_t v;
                YVEC_INIT(&v, 0, yexpr_t);
                yexpr_set_list(&e, v);
                $$ = e;
           };

value: TOK_QUOTE quoted_value {
        ydbg_print("found quoted value\n");
        $$ = $2;
     }
     | TOK_ATOM {
        ydbg_print("found ID %s\n", $1);
        ystr_t sym = ystr_new(NULL);
        ystr_set_owned(&sym, $1);
        yref_t ref = yref_new_str(&sym);
        yexpr_t expr = yexpr_new();
        yexpr_set_ref(&expr, ref);
        $$ = expr;
     }
     | literal;

quoted_value: TOK_ATOM {
        ydbg_print("found atom %s\n", $1);
        yexpr_t expr = yexpr_new();
        yexpr_set_atom_name(&expr, $1);
        free($1);
        $$ = expr;
     } | literal;

literal: TOK_NUMBER_LITERAL {
        ydbg_print("found number %lld\n", $1);
        yexpr_t expr = yexpr_new();
        yexpr_set_number(&expr, $1);
        $$ = expr;
     }
     | TOK_STRING_LITERAL {
        ydbg_print("found string %s\n", $1);
        yexpr_t expr = yexpr_new();
        ystr_t str = ystr_new(NULL);
        ystr_set_owned(&str, $1);
        yexpr_set_str(&expr, str);
        $$ = expr;
     };

%%

int y_bison_parse(FILE* in, yvec_t* out_exprs, ystr_t* ystr_error) {
    void* scanner;
    int r;
    if (0 != (r = yylex_init(&scanner))) {
        error(r, 0, "couldn't initialize scanner!");
        exit(1);
    }
    #ifndef DEBUG
    FILE* out = fopen("/dev/null", "w");
    #else
    FILE* out = stdout;
    #endif
    
    yyset_in(in, scanner);
    yyset_out(out, scanner);

    YVEC_INIT(out_exprs, 16, yexpr_t);

    int ret = yyparse(scanner, out_exprs, ystr_error);

#ifndef DEBUG
    fclose(out);
#endif
    int lex_destroy_ok = yylex_destroy(scanner);
    assert(0 == lex_destroy_ok);
    return ret;
}

void yyerror(void* _scanner, void* _output, ystr_t* ystr_error, char const* s) {
    ystr_t s2 = ystr_new(NULL);
    ystr_set_owned(&s2, (char*)s); // no destroy!
    ystr_append(ystr_error, &s2);
}