I dont get the error, please can you help me out, here is the .l and .y file.thanks.
%{
#include "ifanw.tab.h"
extern int yylval;
%}
%%
"=" { return EQ; }
"!=" { return NE; }
"<" { return LT; }
"<=" { return LE; }
">" { return GT; }
">=" { return GE; }
"+" { return PLUS; }
"-" { return MINUS; }
"*" { return MULT; }
"/" { return DIVIDE; }
")" { return RPAREN; }
"(" { return LPAREN; }
":=" { return ASSIGN; }
";" { return SEMICOLON; }
"IF" { return IF; }
"THEN" { return THEN; }
"ELSE" { return ELSE; }
"FI" { return FI; }
"WHILE" { return WHILE; }
"DO" { return DO; }
"OD" { return OD; }
"PRINT" { return PRINT; }
[0-9]+ { yylval = atoi(yytext); return NUMBER; }
[a-z] { yylval = yytext[0] - 'a'; return NAME; }
\ { ; }
\n { nextline(); }
\t { ; }
"//".*\n { nextline(); }
. { yyerror("illegal token"); }
%%
Yacc-file
%start ROOT
%token EQ
%token NE
%token LT
%token LE
%token GT
%token GE
%token PLUS
%token MINUS
%token MULT
%token DIVIDE
%token RPAREN
%token LPAREN
%token ASSIGN
%token SEMICOLON
%token IF
%token THEN
%token ELSE
%token FI
%token WHILE
%token DO
%token OD
%token PRINT
%token NUMBER
%token NAME
%%
ROOT:
stmtseq { execute($1); }
;
statement:
designator ASSIGN expression { $$ = assignment($1, $3); }
| PRINT expression { $$ = print($2); }
| IF expression THEN stmtseq ELSE stmtseq FI
{ $$ = ifstmt($2, $4, $6); }
| IF expression THEN stmtseq FI
{ $$ = ifstmt($2, $4, empty()); }
| WHILE expression DO stmtseq OD { $$ = whilestmt($2, $4); }
;
stmtseq:
stmtseq SEMICOLON statement { $$ = seq($1, $3); }
| statement { $$ = $1; }
;
expression:
expr2 { $$ = $1; }
| expr2 EQ expr2 { $$ = eq($1, $3); }
| expr2 NE expr2 { $$ = ne($1, $3); }
| expr2 LT expr2 { $$ = le($1, $3); }
| expr2 LE expr2 { $$ = le($1, $3); }
| expr2 GT expr2 { $$ = gt($1, $3); }
| expr2 GE expr2 { $$ = gt($1, $3); }
;
expr2:
expr3 { $$ == $1; }
| expr2 PLUS expr3 { $$ = plus($1, $3); }
| expr2 MINUS expr3 { $$ = minus($1, $3); }
;
expr3:
expr4 { $$ = $1; }
| expr3 MULT expr4 { $$ = mult($1, $3); }
| expr3 DIVIDE expr4 { $$ = divide ($1, $3); }
;
expr4:
PLUS expr4 { $$ = $2; }
| MINUS expr4 { $$ = neg($2); }
| LPAREN expression RPAREN { $$ = $2; }
| NUMBER { $$ = number($1); }
| designator { $$ = $1; }
;
designator:
NAME { $$ = name($1); }
;
%%
I have another question, is there a possibility to implement a JMP instruction with flex/bison like in Assembler to go to a label like my example, thanks for your help.
:L1
IF FLAG AND X"0001"
EVT 23;
ELSE
WAIT 500 ms;
JMP L1;
END IF;
EDIT: I put the old answer to the end
Here is the promised more detailed example:
usually I begin with an example file of the desired language:
The next step is to create a lexer+parser combination where the previous file passes.
Here comes the lexer (generate the source with
flex -o lexer.c lexer.l
). Also note that the lexer source depends on the parser sources (because of the TOKEN_* constants), so bison must be run before compiling the lexer source:and the parser (compile with
bison -d -o parser.c parser.y
, the-d
tells bison to create the parser.h header file with some stuff the lexer needs)After
gcc parser.c lexer.c -o toylang-noop
the call oftoylang-noop < example.toy
must run without any error. So now the parser itself works and can parse the example script.The next step is to create a so called abstract syntax tree of the grammar. At this point I start with the augmenting of the parser by defining different types to the tokens and rules, as well as inserting rules to each parsing step.
As you can see, the main part when generating the AST is to create the nodes of the AST when a certain rule of the parser was passed. Since bison maintains a stack of the current parsing process itself, is is only needed to assign the current parsing status to the elements of the stack (these are the
$$=foo(bar)
lines)The target is the following structure in memory:
To get this graph, there is the generating code needed, astgen.h:
astgen.c:
You can see here that the generating of the AST elements is a rather monotone job. After the step is done, the program still does nothing, but the AST can be viewed in a debugger.
The next step is to write the interpreter. This is astexec.h:
Well, this looks friendly. The Interpreter itself is simple, despite it's length. The most functions deals with only a particular kind of AstElement. The correct function is selected by the dispatchExpression and dispatchStatement functions. The dispatch functions looks for the target function in the valExecs and runExecs arrays.
astexec.c:
Now the interpreter is complete, and the example can be run, after the main function is updated:
Now the interpreter for this language works. Note that there are some limitations within this interpreter:
execStmt
function, but to jump between different blocks or levels the execution machinery must be changed dramatically (this is because one can't jump between different stack frames in the interpreter). For example the AST can be transformed into byte code and this byte code is interpreted by a vm.You need to define the grammar for your language. Some thing like this (both lexer and parser are incomplete):
Then you compile this file with
bison -d foo.y -o foo.c
. The-d
switch instruct bison to generate a header with all the tokens the parser uses. Now you create your lexerAfter this you have your lexer and parser done, and "only" need to write the semantic actions for your language.