diff options
Diffstat (limited to 'lib/forlangrm.y')
-rw-r--r-- | lib/forlangrm.y | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/lib/forlangrm.y b/lib/forlangrm.y new file mode 100644 index 0000000..1b7781d --- /dev/null +++ b/lib/forlangrm.y @@ -0,0 +1,237 @@ +%{ +/* This file is part of Eclat. + Copyright (C) 2012 Sergey Poznyakoff. + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +#include "libeclat.h" +#include <grecs.h> +#include <grecs-locus.h> +#include "forlangrm.h" +#include "forlan.h" + +static int yyerror(char *); +union forlan_node *forlan_parse_tree; +%} +%error-verbose +%locations + +%union { + char *string; + union forlan_node *node; + struct grecs_list *list; +}; + +%token <string> STRING IDENT +%token LAST IF ELSE + +%left OR +%left AND +%left NOT + +%type <node> stmt stmt_cond stmt_expr stmt_blk cond bool node comp funcall arg +%type <list> stmtlist complist arglist +%type <string> string + +%% +input : stmtlist + { + forlan_parse_tree = forlan_stmt_from_list($1); + } + ; + +stmtlist : stmt + { + $$ = forlan_stmt_list(); + grecs_list_append($$, $1); + } + | stmtlist stmt + { + grecs_list_append($1, $2); + $$ = $1; + } + ; + +stmt : stmt_cond + | stmt_expr + | stmt_blk + ; + +stmt_blk : '{' stmtlist '}' + { + $$ = forlan_stmt_from_list($2); + } + ; + +stmt_cond : IF cond stmt + { + $$ = forlan_node_create(forlan_type_cond); + $$->cond.expr = $2; + $$->cond.iftrue = $3; + $$->cond.iffalse = NULL; + } + | IF cond stmt ELSE stmt + { + $$ = forlan_node_create(forlan_type_cond); + $$->cond.expr = $2; + $$->cond.iftrue = $3; + $$->cond.iffalse = $5; + } + ; + +cond : bool + ; + +bool : node + { + $$ = forlan_node_create(forlan_type_expr); + $$->expr.opcode = forlan_opcode_node; + $$->expr.arg[0] = $1; + } + | bool AND bool + { + $$ = forlan_node_create(forlan_type_expr); + $$->expr.opcode = forlan_opcode_and; + $$->expr.arg[0] = $1; + $$->expr.arg[1] = $3; + } + | bool OR bool + { + $$ = forlan_node_create(forlan_type_expr); + $$->expr.opcode = forlan_opcode_or; + $$->expr.arg[0] = $1; + $$->expr.arg[1] = $3; + } + | NOT bool + { + $$ = forlan_node_create(forlan_type_expr); + $$->expr.opcode = forlan_opcode_not; + $$->expr.arg[0] = $2; + } + | '(' bool ')' + { + $$ = $2; + } + ; + +node : complist + { + $$ = forlan_node_create(forlan_type_comp); + $$->comp.abs = 0; + $$->comp.node = forlan_stmt_from_list($1); + } + | '.' complist + { + $$ = forlan_node_create(forlan_type_comp); + $$->comp.abs = 1; + $$->comp.node = forlan_stmt_from_list($2); + } + | LAST + { + $$ = forlan_node_create(forlan_type_last); + } + ; + +complist : comp + { + $$ = forlan_stmt_list(); + grecs_list_append($$, $1); + } + | complist '.' comp + { + grecs_list_append($1, $3); + $$ = $1; + } + ; + +comp : IDENT + { + $$ = forlan_node_create(forlan_type_lit); + $$->lit.string = $1; + } + | IDENT '[' string ']' + { + $$ = forlan_node_create(forlan_type_test); + $$->test.comp = $1; + $$->test.value = $3; + } + | funcall + ; + +string : IDENT + | STRING + ; + +funcall : IDENT '(' ')' + { + $$ = forlan_node_create(forlan_type_func); + $$->func.fp = $1; //FIXME + $$->func.args = NULL; + } + | IDENT '(' arglist ')' + { + $$ = forlan_node_create(forlan_type_func); + $$->func.fp = $1; //FIXME + $$->func.args = $3; + } + ; + +arglist : arg + { + $$ = forlan_stmt_list(); + grecs_list_append($$, $1); + } + | arglist ',' arg + { + grecs_list_append($1, $3); + $$ = $1; + } + ; + +arg : node + | STRING + { + $$ = forlan_node_create(forlan_type_lit); + $$->lit.string = $1; + } + ; + +stmt_expr : funcall ';' + ; +%% +static int +yyerror(char *s) +{ + grecs_error(&yylloc, 0, "%s", s); + return 0; +} + +int +forlan_parser() +{ + yydebug = debug_level(forlan_dbg) >= FORLAN_DBG_GRAM; + return yyparse(); +} + +int +forlan_parse(const char *input, size_t length, struct grecs_locus_point *pt) +{ + int rc; + forlan_lex_begin(input, length, pt); + rc = forlan_parser(); + forlan_lex_end(); + return rc; +} + + |