ocaml: phase 5.1 calc.ml baseline (11/11 pass) + inline let-rec-and parser fix
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 54s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 54s
Recursive-descent calculator parses '(1 + 2) * 3 + 4' = 13. Two parser bugs fixed: 1. parse-let now handles inline 'let rec a () = ... and b () = ... in body' via new (:let-rec-mut BINDINGS BODY) and (:let-mut BINDINGS BODY) AST shapes; eval handles both. 2. has-matching-in? lookahead no longer stops at 'and' — 'and' is internal to let-rec, not a decl boundary. Without this fix, the inner 'let rec a () = ... and b () = ...' inside a let-decl rhs would have been treated as the start of a new top-level decl. Baseline exercises mutually-recursive functions, while-loops, ref-cell imperative parsing, and ADT-based AST construction.
This commit is contained in:
76
lib/ocaml/baseline/calc.ml
Normal file
76
lib/ocaml/baseline/calc.ml
Normal file
@@ -0,0 +1,76 @@
|
||||
(* Baseline: recursive-descent calculator for "+", "*", parens, ints. *)
|
||||
type expr =
|
||||
| Lit of int
|
||||
| Add of expr * expr
|
||||
| Mul of expr * expr
|
||||
;;
|
||||
|
||||
let parse_input src =
|
||||
let pos = ref 0 in
|
||||
let peek () = if !pos < String.length src then String.get src !pos else "" in
|
||||
let advance () = pos := !pos + 1 in
|
||||
let skip_ws () =
|
||||
while !pos < String.length src && peek () = " " do advance () done
|
||||
in
|
||||
|
||||
let rec parse_atom () =
|
||||
skip_ws () ;
|
||||
if peek () = "(" then begin
|
||||
advance () ;
|
||||
let e = parse_expr () in
|
||||
skip_ws () ;
|
||||
advance () ; (* consume ')' *)
|
||||
e
|
||||
end
|
||||
else
|
||||
let start = !pos in
|
||||
let rec digits () =
|
||||
if !pos < String.length src then
|
||||
let c = peek () in
|
||||
if c >= "0" && c <= "9" then begin advance () ; digits () end
|
||||
else ()
|
||||
in
|
||||
digits () ;
|
||||
let n = Int.of_string (String.sub src start (!pos - start)) in
|
||||
Lit n
|
||||
|
||||
and parse_term () =
|
||||
skip_ws () ;
|
||||
let lhs = ref (parse_atom ()) in
|
||||
let rec loop () =
|
||||
skip_ws () ;
|
||||
if peek () = "*" then begin
|
||||
advance () ;
|
||||
lhs := Mul (!lhs, parse_atom ()) ;
|
||||
loop ()
|
||||
end
|
||||
in
|
||||
loop () ;
|
||||
!lhs
|
||||
|
||||
and parse_expr () =
|
||||
skip_ws () ;
|
||||
let lhs = ref (parse_term ()) in
|
||||
let rec loop () =
|
||||
skip_ws () ;
|
||||
if peek () = "+" then begin
|
||||
advance () ;
|
||||
lhs := Add (!lhs, parse_term ()) ;
|
||||
loop ()
|
||||
end
|
||||
in
|
||||
loop () ;
|
||||
!lhs
|
||||
in
|
||||
parse_expr ()
|
||||
;;
|
||||
|
||||
let rec eval e =
|
||||
match e with
|
||||
| Lit n -> n
|
||||
| Add (a, b) -> eval a + eval b
|
||||
| Mul (a, b) -> eval a * eval b
|
||||
;;
|
||||
|
||||
(* (1 + 2) * 3 + 4 = 9 + 4 = 13 *)
|
||||
eval (parse_input "(1 + 2) * 3 + 4")
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"calc.ml": 13,
|
||||
"closures.ml": 315,
|
||||
"exception_handle.ml": 4,
|
||||
"expr_eval.ml": 16,
|
||||
|
||||
Reference in New Issue
Block a user