Commit c8724a27 authored by Mark Wheelhouse's avatar Mark Wheelhouse
Browse files

provided files for the WACC project (in C)

parents
# Sample Makefile for the WACC Compiler Lab: edit this to build your own compiler
all:
cd src && make
clean:
cd src && make clean
.PHONY: all clean
This is the provided git repository for the WACC Lab in C. You should work in this
repository regularly committing and pushing your work back to GitLab.
----------------------------
Provided files/directories
----------------------------
> src <
The src directory contains a simple lexer and parser for a basic calculator
grammar. It also contains an simple abstract syntax tree and a visitor for this
tree to demonstrate the interface with the lexer/parser files along with a
makefile that builds this example project. There are some further details on
these provided files in the src directory README file. You are expected to
extend or rewrite these files to build your WACC compiler.
> compile <
The compile script should be edited to provide a frontend interface to your WACC
compiler. You are free to change the language used in this script, but do not
change its name. This script currently writes a TODO: message to the console,
but you should update it to call the the main method of your compiler with
appropriate arguments. Note that the lab's automated testing service will be
using this script as the access point to your compiler.
> LexAndYaccTutorial.pdf <
A tutorial document that describes the basics of Lex and Yaxx and also details
how to create a lexer and parser project similar to that found in the src
directory.
> Makefile <
Your Makefile should be edited so that running 'make' in the root directory
builds your WACC compiler. Currently this makefile will delegate to running
'make' in the src directory. You are free to modify this build structure in any
way that you wish.
#!/usr/bin/ruby
# Ruby front-end for your compiler.
# You are free to change the language used for this script,
# but do *not* change its name.
puts "TODO: setup this script to call your WACC compiler"
// definitions
%{
#include <stdlib.h>
#include "ast.h"
#include "y.tab.h"
void yyerror(char* s);
%}
digit [0-9]
%%
// rules
{digit}+ {
yylval.val = atoi(yytext);
return INTEGER;
}
"+" return PLUS;
"-" return MINUS;
"(" return OPEN_PARENTHESES;
")" return CLOSE_PARENTHESES;
/* anything else is an error */
. yyerror("Unknown Character");
%%
// subroutines
int yywrap(void) {
return 1;
}
//definitions
%{
#include <stdio.h>
#include <stdlib.h>
#include "ast.h"
// prototypes
treeNode* make_binop_node(treeNode* op, treeNode* left, treeNode* right);
treeNode* make_op_node(char* op);
treeNode* make_int_node(int val);
void free_tree(treeNode* t);
void visit(treeNode* t);
void yyerror(char* s);
int yylex();
%}
//declare parser traversal types
%union {
int val; // integer value
treeNode* tree; // tree node pointer
};
// declare parser token types
%token <val> INTEGER
%token PLUS
%token MINUS
%token OPEN_PARENTHESES
%token CLOSE_PARENTHESES
// decalre return types for parser rules
%type <tree> expr binaryOper
%%
// grammar rules
prog: prog expr { printf("Parsing...\n"); visit($2); free_tree($2);}
| // Empty Program
;
expr: INTEGER { $$ = make_int_node($1); }
| expr binaryOper expr { $$ = make_binop_node($2,$1,$3); }
| OPEN_PARENTHESES expr CLOSE_PARENTHESES { $$ = $2; }
;
binaryOper: PLUS { $$ = make_op_node("PLUS"); }
| MINUS { $$ = make_op_node("MINUS"); }
;
%%
//subroutines
// create binary operator node
treeNode* make_binop_node(treeNode* op, treeNode* left, treeNode* right) {
treeNode* t;
// allocate memory for node
if ((t = malloc(sizeof(treeNode))) == NULL){
yyerror("out of memory");
}
t->nodeType = binopT;
t->binop.op = op;
t->binop.left = left;
t->binop.right = right;
return t;
}
// create operator node
treeNode* make_op_node(char* op) {
treeNode* t;
// allocate memory for node
if ((t = malloc(sizeof(treeNode))) == NULL){
yyerror("out of memory");
}
t->nodeType = opT;
t->op.opstr = op;
return t;
}
//create integer node
treeNode* make_int_node(int val) {
treeNode* t;
// allocate memory for node
if ((t = malloc(sizeof(treeNode))) == NULL){
yyerror("out of memory");
}
t->nodeType = intT;
t->in.value = val;
return t;
}
void free_tree(treeNode* t) {
if(!t){return;}
if(t->nodeType == binopT){
free_tree(t->binop.left);
free_tree(t->binop.right);
}
free(t);
}
void yyerror(char* s) {
fprintf(stdout, "\n%s\n", s);
}
int main(void) {
yyparse();
return 0;
}
#include <stdio.h>
#include "ast.h"
#include "y.tab.h"
void print_indent(int indent);
int indent = 2;
// basic tree visitor (prints tree representation)
void visit(treeNode* t) {
if(!t){
printf("Null ptr encountered!");
return;
}
switch(t->nodeType){
case opT: print_indent(indent);
printf("OP(%s)\n", t->op.opstr);
break;
case intT: print_indent(indent);
printf("INT(%d)\n", t->in.value);
break;
case binopT: print_indent(indent);
printf("BINOP:\n");
indent += 2;
visit(t->binop.op);
visit(t->binop.left);
visit(t->binop.right);
indent -= 2;
break;
default: printf("Unexpected Case! \n");
}
}
// printing helper
void print_indent(int indent) {
for(int i=0; i<indent; i++){
printf(" ");
}
}
# makefile for a simple C compiler buildchain
all: basic
y.tab.c: BasicParser.yacc
yacc -d BasicParser.yacc
lex.yy.c: BasicLexer.lex BasicParser.yacc
lex BasicLexer.lex
y.tab.o: y.tab.c lex.yy.c
gcc -c y.tab.c lex.yy.c
basic: y.tab.o lex.yy.o BasicVisitor.c
gcc y.tab.o lex.yy.o BasicVisitor.c -o basic
clean:
rm basic y.tab.* lex.yy.*
.PHONY: clean all
TODO: write your compiler in this directory.
------------------------------------
Provided files - additional details
------------------------------------
The files in this directory provide a simple example for lexing and parsing a
small calculator grammar with the lex and yacc tools (also known as Flex and
Bison). You are free to modify any or all parts of these files, but must use
the lex and yacc tools in your project.
> ast.h <
This header file gives the C struct definition of a basic abstract syntax tree
(AST) consisting of a general treeNode type that is then specialised to
different concrete node types. A tree of this type is generated by the example
calculator parser.
> BasicLexer.lex <
This is the lex configuration file for the example calculator lexer. The lexer
defines a small token set for the calculator's syntax which are passed onto the
calculator parser also found in this directory. You will probably want to extend
this lexer to the full WACC language.
> BasicParser.yacc <
This is the yacc configuration file for the example calculator parser. The
parser defines a small grammar for the calculator's syntact which is used to
construct an AST representing the input program and run a traversal over the
tree which visits every one. You will probably want to extend this parser to the
full WACC language.
> BasicVisitor.c <
This is an example tree traversal program which is called by the calculator
parser to visit every node of the generated AST and print a view of its
structure. You will probably want to extend this visitor to carry out semantic
checking for the full WACC language.
> Makefile <
This build scipt takes the provided lex and yacc configuration files and
generates C that implements a lexer and parser for the calculator example. This
code is then compiled and link with the provided example AST and tree visitor
to produce a simple example executable called 'basic'.
> basic <
once you have run 'make' in this directory, you will have a simple executable
which implements the lexer, parser and tree printer described above. This can be
run over an input program to print a representation of the produced AST to the
console.
It is run by calling ./basic on the command line. You will need to type in your
input program and then close the input stream with ctrl-D.
Rather than typing your input programs in by hand, you can pass the executable a
file to read by piping it in through stdin with
./basic < testfile
When using the executable in this way you won't need to hit ctrl-D to close the
input stream as the EOF character in the file does this for you.
--------------------------
Useful Lex/Yacc resources
--------------------------
The provided calculator example was created with the help of the following
resources which you may find useful to your further development:
http://dinosaur.compilertools.net
http://dinosaur.compilertools.net/lex/index.html
http://dinosaur.compilertools.net/yacc/index.html
http://www.cs.man.ac.uk/~pjj/cs211/ho/node8.html
../LexAndYaccTutorial.pdf
typedef enum { binopT, opT, intT } treeType;
// operator node
typedef struct {
char* opstr; // operator name
} opNode;
// integer node
typedef struct {
int value; //value of integer
} intNode;
// binary operator node
typedef struct {
struct treeNode* op; // operator node
struct treeNode* left; // left subtree
struct treeNode* right; // right subtree
} binopNode;
// general tree node wrapper
typedef struct treeNode {
treeType nodeType; // type of node
union {
binopNode binop; // binary operator
opNode op; // operators
intNode in; // integers
};
} treeNode;
Markdown is supported
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