Commit 93cb2740 authored by Peter Faber's avatar Peter Faber
Browse files

init t-05

parent 12989b13
all: parser
OBJS = parser.o \
main.o \
tokens.o
LLVMCONFIG = llvm-config-6.0
CPPFLAGS = -g `$(LLVMCONFIG) --cppflags` -std=c++11
LDFLAGS = `$(LLVMCONFIG) --ldflags` -rdynamic
LIBS = `$(LLVMCONFIG) --libs`
clean:
$(RM) -rf parser.cpp parser.hpp parser tokens.cpp tokens.hpp tokens $(OBJS)
parser.cpp: parser.y
bison -d -o $@ $^
parser.hpp: parser.cpp
tokens.cpp: tokens.l
flex --header-file=$(subst .cpp,.hpp,$@) -o $@ $^
tokens.hpp: tokens.cpp
%.o: %.cpp
$(CXX) -c $(CPPFLAGS) -o $@ $<
parser: $(OBJS)
$(CXX) -o $@ $(OBJS) $(LIBS) $(LDFLAGS)
test: parser example.txt
cat example.txt | ./$^
distclean: clean
$(RM) -rf .depend ./parser.cpp ./parser.hpp ./tokens.cpp ./tokens.hpp
.PHONY: clean distclean
depend: .depend
.depend: parser.cpp tokens.cpp parser.hpp tokens.hpp
$(CXX) `$(LLVMCONFIG) --cppflags` $(FLAGS) $(INCLUDE) -M *.cpp > .depend || true
$(CXX) `$(LLVMCONFIG) --cppflags` $(FLAGS) $(INCLUDE) -M *.hpp >> .depend || true
-include .depend
extern int printi(int val);
int do_math(int a) {
int x = a * 5;
return x + 3;
}
printi(do_math(8)-1);
#include <iostream>
#include <cstdlib>
// has to be included first, so that PNode is available
#include "node.hpp"
#include "parser.hpp"
#include "tokens.hpp"
int main(int argc,char**argv) {
// if a file name is supplied, open that file and
// use it for yyin (parser input)
if (argc > 1) {
if(nullptr==(yyin = fopen(argv[1], "r"))){
std::cerr<<std::string("Could not open file ")+argv[1]<<std::endl;
}
}
yyparse();
std::cout << "Result:" << std::endl << programBlock << std::endl;
return 0;
}
#ifndef _NODE_H_
#define _NODE_H_
#include <memory>
#include <iostream>
/// possible binary expression operators:
// plus, minus, multiplication, division
typedef enum opEnum {
PLUS, MINUS, MUL, DIV
} BinOp;
/// possible comparison operators:
// non-equal, less-than, less-equal, equal, greater-equal,
// greater-than
typedef enum compEnum {
NE, LT, LE, EQ, GE, GT
} CompOp;
// some syntactic sugar for creating AST nodes
// type of pointer to a node (or subclass)
// FOR THE TIME BEING, WE WILL ONLY USE INTs!
#define PNODE(type) int
// later: type of pointer to Node (or subclass)
// for now: everything is an integer
typedef PNODE(Node) PNode;
extern PNode programBlock; /* the top level root node of our final AST */
#endif
%{
#include "node.hpp"
#include <cstdlib>
#include "tokens.hpp"
PNode programBlock; /* the top level root node of our final AST */
void yyerror(const char *s) { fprintf(stderr,"Error in line %d: %s\n", yylineno,s);exit(1); }
%}
/* Represents the many different ways we can access our data */
%union {
PNode value;
}
/* Define the type of node our terminal symbols represent.
The types refer to the %union declaration above.
*/
%token TINT_T
%token TIDENTIFIER
%token<value> TINTEGER
%token TASSIGN
// TODO: change into
// TxOPy: < x=C: Comparison, x=B: Binary > operator; y=precedence
%token TLT TLE TEQ TNE TGE TGT
%token TLPAREN TRPAREN TLBRACE TRBRACE
%token TSEMICOL TCOMMA
%token TPLUS TMINUS TMUL TDIV
// TODO: Also define a new token for a unary +/- operator
%token TRETURN TEXTERN
%token TIF TELSE
%token TNONE
/* Define the type of node our nonterminal symbols represent.
The types refer to the %union declaration above.
*/
%type <value> ident
%type <value> numeric expr
%type <value> func_decl_args
%type <value> call_args
%type <value> program block
%type <value> stmts
%type <value> stmt block_stmt simple_stmt func_decl extern_decl
%type <value> var_decl_with_init var_decl
%type <value> if_stmt
%type <value> comparison var_init
%start program
%%
program : stmts { programBlock = $1; }
;
stmts : stmt { $$ = $1;
}
| stmts stmt { $$=$2; }
;
stmt : block_stmt | simple_stmt TSEMICOL
;
block_stmt: func_decl | if_stmt
;
simple_stmt: var_decl_with_init { $$ = $1; }
| extern_decl
| expr { $$ = $1; }
| TRETURN expr { $2; }
;
// Note: We disallow empty statement blocks here -- actually
// only, because it makes LLVM code generation simpler!
block : TLBRACE stmts TRBRACE
{ $$ = $2; }
;
type: TINT_T; // ONLY INTEGERS ALLOWED!
var_init: TASSIGN expr { $$ = $2; } | { $$ = 0; } ;
var_decl : type ident { $$ = $2; };
var_decl_with_init: var_decl var_init
{ $$ = $2; }
;
extern_decl : TEXTERN type ident TLPAREN func_decl_args TRPAREN
{ $$ = $5;}
;
func_decl : type ident TLPAREN func_decl_args TRPAREN block
{ $$ = $6;
}
;
func_decl_args: /*blank*/ { $$ = 0; }
| var_decl { $$ = $1; }
| func_decl_args TCOMMA var_decl
{ $$ = $3;}
;
if_stmt: TIF TLPAREN expr TRPAREN block TELSE block
{ $$ = $7;
}
| TIF TLPAREN expr TRPAREN block
{ $$ = $5; }
;
expr : ident TLPAREN call_args TRPAREN
{ $$ = $3;}
| ident TASSIGN expr
{ $$ = $3;}
| ident
| numeric
| expr TMUL expr { $$ = ( $1 * $3 ); }
| expr TDIV expr { $$ = ( $1 / $3 ); }
| expr TPLUS expr { $$ = ( $1 + $3 ); }
| expr TMINUS expr { $$ = ( $1 - $3 ); }
| comparison
| TLPAREN expr TRPAREN { $$ = $2; }
// TODO: Also include rules for unary +/- operator
;
ident : TIDENTIFIER { $$ = 0; }
;
numeric : TINTEGER { $$ = $1; }
;
call_args : /*blank*/ { $$ = 0; }
| expr
| call_args TCOMMA expr
{ $$=$3;
}
;
// Hint: Here's how an application of a binary
// operator [here: comparison] can look like,
// if the rule determines precedence, and the
// actual operator is coded in additional info
comparison : expr TCOP1 expr
{
switch($2){
case NE:
$$ = ( $1 != $3 );
break;
case LT:
$$ = ( $1 < $3 );
break;
case LE:
$$ = ( $1 <= $3 );
break;
case EQ:
$$ = ( $1 == $3 );
break;
case GE:
$$ = ( $1 >= $3 );
break;
case GT:
$$ = ( $1 > $3 );
break;
}
}
;
%%
%{
#include <cstdio>
#include <string>
#include "node.hpp"
#include "parser.hpp"
%}
%option noyywrap
%option yylineno
%%
[ \t\n] ;
"//".*$ ;
"extern" {return TEXTERN;}
"return" {return TRETURN;}
"int" {return TINT_T;}
"if" {return TIF;}
"else" {return TELSE;}
[a-zA-Z_][a-zA-Z0-9_]* {return TIDENTIFIER;}
[0-9]+ {yylval.value=std::stoi(yytext);return TINTEGER;}
"=" {return TASSIGN;}
"==" {return TEQ;}
"!=" {return TNE;}
"<" {return TLT;}
"<=" {return TLE;}
">" {return TGT;}
">=" {return TGE;}
"(" {return TLPAREN;}
")" {return TRPAREN;}
"{" {return TLBRACE;}
"}" {return TRBRACE;}
"," {return TCOMMA;}
";" {return TSEMICOL;}
"+" {return TPLUS;}
"-" {return TMINUS;}
"*" {return TMUL;}
"/" {return TDIV;}
. {fprintf(stderr,"Unknown token '%s' in line %d!\n",yytext,yylineno); yyterminate();}
%%
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment