/////////////
// Compile
/////////////
bison -d basic.y
flex basic.l
g++ basic.tab.c lex.yy.c -ll
/////////////
// Example Inputs
/////////////
LET x = 5
IF x THEN
PRINT x
IF x + 2 THEN
PRINT x + 2
ENDIF
ENDIF
/////////////
// basic.y
/////////////
%define parse.error detailed
/* This line does not work in older versions of Bison,
if you get an immediate syntax error, try this instead:
%error-verbose
*/
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern int yylineno;
int yylex(void);
void yyerror(const char *s);
%}
%union {
char *s;
}
%token LET PRINT IF THEN ELSE ENDIF EOL
%token <s> ATOM
%type <s> expr
%left '+'
%%
program
: /* empty */
| program line
;
line
: LET ATOM '=' expr EOL
{ printf("var %s = %s;\n", $2, $4); }
| PRINT expr EOL
{ printf("console.log(%s);\n", $2); }
| if_stmt
| EOL
{ }
;
if_stmt
: IF expr THEN EOL
{ printf("if (%s) {\n\t", $2); }
block
ENDIF EOL
{ printf("}\n"); }
;
block
: /* empty */
| block line
;
expr
: ATOM
{ $$ = $1; }
| expr '+' expr
{
size_t n = strlen($1) + strlen($3) + 4;
char *buf = (char*)malloc(n);
snprintf(buf, n, "%s + %s", $1, $3);
$$ = buf;
}
;
%%
int main(void) {
yyparse();
return 0;
}
void yyerror(const char *s) {
fprintf(stderr, "Error on line %d: %s\n", yylineno, s);
}
////////////
// basic.l
////////////
%option noyywrap
%option yylineno
%{
#include "basic.tab.h"
#include <string.h>
%}
ID [A-Za-z_][A-Za-z0-9_]*
NUM [0-9]+
%%
"LET" return LET;
"PRINT" return PRINT;
"IF" return IF;
"THEN" return THEN;
"ELSE" return ELSE;
"ENDIF" return ENDIF;
{ID} { yylval.s = strdup(yytext); return ATOM; }
{NUM} { yylval.s = strdup(yytext); return ATOM; }
"=" return '=';
"\n" return EOL;
[ \t\r]+ ;
. return yytext[0];
%%