In this project you will create a parser for a small imperative language. Future parts will involve the complete implementation of an interpreter for this language.
func
f(x:val y:val)
return
x-x/y*y;
endfunc
read k; read n; m := 1; while n-m do begin if f(m k) then skip; else write m; m := m + 1; endThe language has just one data type, integer, and variables are not declared. In the while and if statements a positive expression value is interpreted as true while 0 and negative values means false.
The program reads two integers, k and n, and writes all integers between 1 and n that are multiples of k.
The grammar for the language is given by
program ::= functions statements | statements statement ::= variable ':=' expr ';' | 'skip' ';' | 'begin' statements 'end' | 'if' expr 'then' statement 'else' statement | 'while' expr 'do' statement | 'read' variable ';' | 'write' expr ';' | 'return' expr ';' function ::= 'func' variable '(' {variable ':' ('val' | 'ref')} ')' program 'endfunc' statements ::= {statement} variable ::= letter {letter} functions ::= {function}
expr ::= term expr'
expr' ::= addOp term expr' | empty
term ::= factor term'
term' ::= mulOp factor term' |
empty
factor::= num | var |
'(' expr
')' | funCall
funCall ::= var '(' {expr} ')'
addOp ::= '+'
| '-'
mulOp ::= '*'
| '/'
The first thing you should do is modify the parser for expressions that you were given to handle function calls. We need to modify the data type for expressions to handle function calls:
data
Expr = Num Integer | Var String | Add Expr Expr | Sub Expr Expr |
Mul Expr Expr | Div Expr Expr | Func String [Expr]
deriving Show
The option Func String [Expr]
represents a function call with the
String for the function name and the list of expressions for the actual
arguments of the call.
Now modify the parser for the change in the grammar.
Secondly, you need to write a parser for statements given the following data type:
data
Statement =
Assignment
String Expr |
Skip |
Begin
[Statement] |
If Expr
Statement Statement |
While Expr
Statement |
Read String
|
Write Expr
|
Return Expr
deriving
Show
Start this by defining a parsing function for each kind of statement. If the parser has accepted the first reserved word in a statement, you should use require rather than accept to parse other reserved words or symbols in order to get better error messages in case of failure. An example:
assignment = word #- accept
":="
# expr #- require ";"
>->
buildAss
buildAss (v, e) = Assignment v e
Use the functions for each kind of statement to define a parsing function for an arbitrary statement.
Next you will need to write a parser which will accept a
function definition using the data type:
data Function = Function
String [(String,String)] Program
deriving Show
This data type has a String for the name of the function and a list for all the formal arguments. The list contains pairs containing the argument name along with the type "val" or "ref".
Finally, write the parser for the entire program using the
data type:
data Program = Program
[Function] [Statement] deriving Show
This data type contains a list of function definitions and the list of statements that make up the program.
Given that the function program parses a program, the following code can be used to test your parsing. The code reads the program from a file and prints the result of the parse. You can then create test files in your Eclipse project.
main1 =
do
putStr
"Filename: "
name <-
getLine
contents <-
readFile name
putStr
(show
(program contents))
Send me your modified zipped project in the dropbox in BlackBoard.