I think this is a new record, another update just before a week passes! 🥳
I am here to present the first prototype of the new bison parser:
// parser.y
/*
* This file is part of EasyCodeIt.
*
* Copyright (C) 2021 TheDcoder <TheDcoder@protonmail.com>
*
* EasyCodeIt 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 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
*/
%code top {
#define _GNU_SOURCE /* Required to enable (v)asprintf */
#include <stdio.h>
#include <string.h>
}
%union {
char *str;
}
%token UNKNOWN
%token WS
%token COMMENT DIRECTIVE
%token <str> NUMBER STRING BOOL
%token WORD
%token MACRO VARIABLE
%token OPERATOR BRACKET DOT COMMA
/* Operators */
%precedence '?'
%precedence ':'
%left AND "And" OR "Or"
%left LT '<' GT '>' LTE "<=" GTE ">=" EQU '=' NEQ "<>" SEQU "=="
%left '&'
%left '+' '-'
%left '*' '/'
%left '^'
%left NOT "Not"
%precedence INVERSION
%precedence GROUPING
%type <str> expression
%{
int yylex();
void yyerror(const char *s);
%}
%%
exp-list: /* nothing */
| expression {puts($1);}
expression: NUMBER {$$ = strdup($1);}
| expression '?' expression ':' expression {asprintf(&$$, " (%s ? %s : %s) ", $1, $3, $5);}
| expression "And" expression {asprintf(&$$, " (%s And %s) ", $1, $3);}
| expression "Or" expression {asprintf(&$$, " (%s Or %s) ", $1, $3);}
| expression '<' expression {asprintf(&$$, " (%s < %s) ", $1, $3);}
| expression '>' expression {asprintf(&$$, " (%s > %s) ", $1, $3);}
| expression '=' expression {asprintf(&$$, " (%s = %s) ", $1, $3);}
| expression "<=" expression {asprintf(&$$, " (%s <= %s) ", $1, $3);}
| expression ">=" expression {asprintf(&$$, " (%s >= %s) ", $1, $3);}
| expression "<>" expression {asprintf(&$$, " (%s <> %s) ", $1, $3);}
| expression "==" expression {asprintf(&$$, " (%s == %s) ", $1, $3);}
| expression '&' expression {asprintf(&$$, " (%s & %s) ", $1, $3);}
| expression '+' expression {asprintf(&$$, " (%s + %s) ", $1, $3);}
| expression '-' expression {asprintf(&$$, " (%s - %s) ", $1, $3);}
| expression '*' expression {asprintf(&$$, " (%s * %s) ", $1, $3);}
| expression '/' expression {asprintf(&$$, " (%s / %s) ", $1, $3);}
| expression '^' expression {asprintf(&$$, " (%s ^ %s) ", $1, $3);}
| "Not" expression {asprintf(&$$, " (Not %s) ", $2);}
| '-' expression %prec INVERSION {asprintf(&$$, " (-%s) ", $2);}
| '(' expression ')' %prec GROUPING {asprintf(&$$, " (%s) ", $2);}
%%
void start_parser() {
yyparse();
}
void yyerror(char const *s) {
fputs(s, stderr);
fputs("\n", stderr);
}
This version can only handle numeric expressions, and the output is just a string with an excessive amount of brackets to show the correct order of evaluation. It ain't pretty but it does the job 😛
Here are a few sample inputs I tried:
> echo '1 + 2' | ./eci /dev/fd/0
(1 + 2)
> echo '-((1 + 2) / 3) * 4' | ./eci /dev/fd/0
( (- ( ( ( (1 + 2) ) / 3) ) ) * 4)
> echo '42 ? 123 ? 86 : -((1 + 2) / 3) * 4 : 007' | ./eci /dev/fd/0
(42 ? (123 ? 86 : ( (- ( ( ( (1 + 2) ) / 3) ) ) * 4) ) : 007)
(the output is the line of text below the >
shell prompt)
Even though this is very primitive, it has served as proof that I can use bison to write a proper parser, now I can move onto the more intricate details of parsing such as evaluating values and constructing a syntax tree to represent the code.
I will keep you guys updated on the progress, hope the next update comes as soon as this one 🤞