Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ocamllex + Menhir version of TinyLang #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ocamllex+menhir/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
_build/
tiny
12 changes: 12 additions & 0 deletions ocamllex+menhir/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
OCAMLBUILD := ocamlbuild -no-links -use-menhir -menhir "menhir -v"

main:
@$(OCAMLBUILD) main.byte
@ln -sf _build/main.byte tiny

check:
./check

clean:
$(OCAMLBUILD) -clean
rm -f tiny result
8 changes: 8 additions & 0 deletions ocamllex+menhir/check
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash
if [ -f result ] ; then
rm result
fi

for exp in `cat ../testcases`; do
echo $exp | ./tiny >> result
done
19 changes: 19 additions & 0 deletions ocamllex+menhir/eval.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
open Tree

let rec eval_exp (e: exp) =
match e with
| Identifier (_, line) -> failwith ("(line " ^ string_of_int line ^ ") Cannot evaluate the value of an identifier\n")
| IntLiteral (v, _) -> v
| Binary (lhs, rhs, op) -> eval_binary_exp lhs rhs op
and eval_binary_exp (lhs: exp) (rhs: exp) (op: operator) =
match op with
| Plus -> eval_exp lhs + eval_exp rhs
| Minus -> eval_exp lhs - eval_exp rhs
| Mult -> eval_exp lhs * eval_exp rhs
| Div -> eval_exp lhs / eval_exp rhs
;;

let eval_program (prog: program) =
match prog with
| Program e -> eval_exp e
;;
11 changes: 11 additions & 0 deletions ocamllex+menhir/main.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
print_endline "Enter a \"TinyLang\" expression followed by Ctrl-d:";
let lexbuf = Lexing.from_channel stdin in
try
let prog = Tiny_parser.program Tiny_lexer.token lexbuf in
print_string "Pretty print: ";
Pretty.pretty_program prog;
let evaluated_val = Eval.eval_program prog in
print_endline ("Evaluated value: " ^ string_of_int evaluated_val)
with
| Tiny_parser.Error -> print_endline "Parse error"
| Failure msg -> print_endline ("Error: " ^ msg)
39 changes: 39 additions & 0 deletions ocamllex+menhir/pretty.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
open Tree

let rec pretty_exp (e: exp) =
match e with
| Identifier (id, _) -> print_string id
| IntLiteral (v, _) -> print_string (string_of_int v)
| Binary (lhs, rhs, op) -> pretty_binary_exp lhs rhs op
and pretty_binary_exp (lhs: exp) (rhs: exp) (op: operator) =
match op with
| Plus ->
print_string "(";
pretty_exp lhs;
print_string " + ";
pretty_exp rhs;
print_string ")"
| Minus ->
print_string "(";
pretty_exp lhs;
print_string " - ";
pretty_exp rhs;
print_string ")"
| Mult ->
print_string "(";
pretty_exp lhs;
print_string " * ";
pretty_exp rhs;
print_string ")"
| Div ->
print_string "(";
pretty_exp lhs;
print_string " / ";
pretty_exp rhs;
print_string ")"
;;

let pretty_program (prog: program) =
match prog with
| Program e -> pretty_exp e; print_string "\n"
;;
31 changes: 31 additions & 0 deletions ocamllex+menhir/tiny_lexer.mll
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
open Tiny_parser
open Lexing

(* Get the text of the current buffer *)
let get_text = Lexing.lexeme
let get_line_num buf = let p = buf.lex_curr_p in p.pos_lnum

}
(* Helper regex definitions *)
let letter = ['a'-'z' 'A'-'Z']
let digit = ['0'-'9']

let identifier = ((letter | '_') (letter | digit | '_')*)

rule token = parse
| eof { EOFt }
| (' ' | '\t' | '\n' | '\r') { token lexbuf }

| '(' { LPARENt }
| ')' { RPARENt }

| '+' { PLUSt }
| '-' { MINUSt }
| '*' { MULTt }
| '/' { DIVt }

| identifier { IDENTIFIERt (get_text lexbuf, get_line_num lexbuf) }
| ('0' | ['1'-'9']digit*) { INTVALt (int_of_string (get_text lexbuf), get_line_num lexbuf) }

| _ { failwith ("(line " ^ (string_of_int (get_line_num lexbuf)) ^ ") Unexpected char '" ^ (get_text lexbuf) ^ "'") }
27 changes: 27 additions & 0 deletions ocamllex+menhir/tiny_parser.mly
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
%{

%}

%token EOFt
%token LPARENt RPARENt
%token PLUSt MINUSt MULTt DIVt
%token <int * int> INTVALt
%token <string * int> IDENTIFIERt

%left PLUSt MINUSt
%left MULTt DIVt

%start <Tree.program> program


%%
program: exp EOFt { Tree.Program $1 };

exp: IDENTIFIERt { Tree.Identifier (fst $1, snd $1) }
| INTVALt { Tree.IntLiteral (fst $1, snd $1) }
| LPARENt exp RPARENt { $2 }
| exp MULTt exp { Tree.Binary ($1, $3, Tree.Mult) }
| exp DIVt exp { Tree.Binary ($1, $3, Tree.Div) }
| exp PLUSt exp { Tree.Binary ($1, $3, Tree.Plus) }
| exp MINUSt exp { Tree.Binary ($1, $3, Tree.Minus) }
;
19 changes: 19 additions & 0 deletions ocamllex+menhir/tree.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
type operator =
| Plus
| Minus
| Mult
| Div
;;

type exp =
(* id string, line number *)
| Identifier of string * int
(* literal value, line number *)
| IntLiteral of int * int
(* lhs, rhs, operator *)
| Binary of exp * exp * operator
;;

type program =
Program of exp
;;