This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
|
|
@ -0,0 +1,11 @@
|
|||
type op =
|
||||
| Add
|
||||
| Mul
|
||||
| Div
|
||||
|
||||
type exp =
|
||||
| Int of int
|
||||
| Float of float
|
||||
| Ident of string
|
||||
| Op of op * exp * exp
|
||||
| Call of string * exp
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
type value = VInt of int | VFloat of float
|
||||
|
||||
let value_to_string = function
|
||||
| VInt n -> string_of_int n
|
||||
| VFloat f -> Printf.sprintf "%.6g" f
|
||||
|
||||
let eval_number_op f_int f_float va vb =
|
||||
match (va, vb) with
|
||||
| VInt na, VInt nb -> VInt (f_int na nb)
|
||||
| VFloat fa, VFloat fb -> VFloat (f_float fa fb)
|
||||
| VInt na, VFloat fb -> VFloat (f_float (float_of_int na) fb)
|
||||
| VFloat fa, VInt nb -> VFloat (f_float fa (float_of_int nb))
|
||||
|
||||
let as_float = function
|
||||
| VInt n -> float_of_int n
|
||||
| VFloat f -> f
|
||||
|
||||
let rec eval = function
|
||||
| Ast.Int n -> VInt n
|
||||
| Float f -> VFloat f
|
||||
| Ident "pi" -> VFloat (2. *. Stdlib.acos 0.)
|
||||
| Ident _ -> failwith "unknown ident"
|
||||
| Op (Add, a, b) -> eval_number_op ( + ) ( +. ) (eval a) (eval b)
|
||||
| Op (Mul, a, b) -> eval_number_op ( * ) ( *. ) (eval a) (eval b)
|
||||
| Op (Div, a, b) -> eval_number_op ( / ) ( /. ) (eval a) (eval b)
|
||||
| Call ("sin", e) -> VFloat (Stdlib.sin (as_float (eval e)))
|
||||
| Call _ -> failwith "unknown function"
|
||||
|
||||
let info = Cmdliner.Cmd.info "calc"
|
||||
|
||||
let eval_lb lb =
|
||||
try
|
||||
let expr = Parser.main Lexer.token lb in
|
||||
let v = eval expr in
|
||||
Printf.printf "%s\n" (value_to_string v)
|
||||
with Parser.Error ->
|
||||
Printf.printf "parse error near character %d" lb.lex_curr_pos
|
||||
|
||||
let repl () =
|
||||
while true do
|
||||
Printf.printf ">> %!";
|
||||
let lb = Lexing.from_channel Stdlib.stdin in
|
||||
eval_lb lb
|
||||
done
|
||||
|
||||
let term =
|
||||
let open Cmdliner.Term.Syntax in
|
||||
let+ expr_opt =
|
||||
let open Cmdliner.Arg in
|
||||
value & opt (some string) None & info [ "e" ]
|
||||
in
|
||||
match expr_opt with
|
||||
| Some s -> eval_lb (Lexing.from_string s)
|
||||
| None -> repl ()
|
||||
|
||||
let cmd = Cmdliner.Cmd.v info term
|
||||
let main () = Cmdliner.Cmd.eval cmd |> Stdlib.exit
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
let space = [' ']+
|
||||
|
||||
let digit = ['0'-'9']
|
||||
|
||||
let letter = ['a'-'z']
|
||||
|
||||
let ident = letter+
|
||||
|
||||
rule token = parse
|
||||
| eof { Parser.Eof }
|
||||
| space { token lexbuf }
|
||||
| '\n' { Parser.Eof }
|
||||
| '+' { Parser.Plus }
|
||||
| '*' { Parser.Star }
|
||||
| '/' { Parser.Slash }
|
||||
| '(' { Parser.Lpar }
|
||||
| ')' { Parser.Rpar }
|
||||
| digit+ { Parser.Int (int_of_string (Lexing.lexeme lexbuf)) }
|
||||
| digit+ '.' digit+ { Parser.Float (float_of_string (Lexing.lexeme lexbuf)) }
|
||||
| ident { Parser.Ident (Lexing.lexeme lexbuf) }
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
%token Eof
|
||||
%token<int> Int
|
||||
%token Plus
|
||||
%token Star
|
||||
%token Slash
|
||||
%token Lpar Rpar
|
||||
%token<float> Float
|
||||
%token<string> Ident
|
||||
%start<Ast.exp> main
|
||||
|
||||
%left Plus
|
||||
%left Star Slash
|
||||
|
||||
%{ open Ast %}
|
||||
|
||||
%%
|
||||
|
||||
main: expr Eof { $1 }
|
||||
|
||||
expr:
|
||||
| Int { Int $1 }
|
||||
| expr Plus expr { Op (Add, $1, $3) }
|
||||
| expr Star expr { Op (Mul, $1, $3) }
|
||||
| expr Slash expr { Op (Div, $1, $3) }
|
||||
| Ident Lpar expr Rpar { Call ($1, $3) }
|
||||
| Float { Float $1 }
|
||||
| Ident { Ident $1 }
|
||||
|
||||
%%
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
$ calc -e '1+2'
|
||||
3
|
||||
|
||||
$ calc -e '1+'
|
||||
parse error near character 2
|
||||
|
||||
$ calc -e '1+2.5'
|
||||
3.5
|
||||
|
||||
$ calc -e '1+pi'
|
||||
4.14159
|
||||
|
||||
$ calc -e '1+2*3'
|
||||
7
|
||||
|
||||
$ calc -e '4/2'
|
||||
2
|
||||
|
||||
$ calc -e 'sin (pi / 6)'
|
||||
0.5
|
||||
Loading…
Add table
Add a link
Reference in a new issue