ocaml - Error trying to parse imaginary programming language -
i'm working on language interpreter programming language made up. here's example code, should work dies syntax error @ offset 45.
when reading testcase.
{ foo = { "min" : 1 ,"max" : 5}; foo["min"] }
the correct interpretation first line foo create map , store in variable named foo, second line looks value of field min in record foo, , starting/ending curlies semicolon wrap 2 expressions expr_seq
(i.e. block) evaluates same thing last expr
in it.
a simplified version of parser.mly follows:
%token <int> int %token <string> var %token semi comma colon assign quote %token lbrack rbrack lcurl rcurl %token eof %start <int> main %% main: | eof { failwith "empty input" } | e = exp eof { e } exp: | int { 0 } | e = exp lbrack v = q_var rbrack { (* map lookup *) 0 } | v = var assign e = exp { (* assign var *) 0 } | v = var lbrack f = q_var rbrack assign e = exp { (* assign map field *) 0 } | v = var { printf.printf "lookup %s\n" v; 0 } | lcurl e = expr_seq rcurl { (* block expression *) 0 } | lcurl f = fields rcurl { (* map literal *)0 } fields: | v = q_var colon e = exp { [(v, e)] } | v = q_var colon e = exp comma vt = fields { (v, e) :: vt } q_var: | quote v = var quote { printf.printf "qvar %s\n" v; v } expr_seq: | e = exp {[e]} |e1 = exp semi e2 = expr_seq {e1 :: e2}
trying debug on own, found if removed following | v = var lbrack f = q_var rbrack assign e = exp
parse , run correctly, i'd able set things in maps.
i'm 98% confident problem lies in mly file, simplified version of lexer.mll follows:
{ open parser open printf } rule token = parse | [' ' '\t' '\n'] { token lexbuf } | "=" {assign} | ['1'-'9']['0'-'9']* { int (int_of_string i) } | ['a'-'z']+ v { printf "var %s\n" v;var v } | '{' { lcurl } | '}' { rcurl } | '[' { printf "["; lbrack } | ']' { printf "]"; rbrack } | ';' { semi } | ':' { colon } | ',' { comma } | '"' { quote } | eof { eof } | _ { raise (failure (sprintf "at offset %d: unexpected character.\n" (lexing.lexeme_start lexbuf))) }
and simple ml file is:
open core.std open printf let rec read_all ic = try let ln = input_line ic in ln ^ read_all ic end_of_file -> "";; let () = let linebuf = lexing.from_string (read_all stdin) in try parser.main lexer.token linebuf; printf "done" | failure msg -> fprintf stderr "%s%!" msg | parser.error -> fprintf stderr "syntax error @ offset %d.\n%!" (lexing.lexeme_start linebuf)
edit: here's makefile. parser.mly, lexer.mll, , interpreter.ml second, third, , fourth files above.
all: hb lexer.cmx parser.cmx interpreter.cmx @true hb: interpreter.cmx ocamlfind ocamlopt -o hb -linkpkg -package core -package core_kernel \ -thread -w -10 parser.cmx lexer.cmx interpreter.cmx interpreter.cmx: lexer.cmx ocamlfind ocamlopt -package core -package core_kernel -thread -w -10 \ -c interpreter.ml lexer.cmx: lexer.ml parser.cmx ocamlfind ocamlopt -c lexer.ml parser.cmx: parser.mly menhir --ocamlc "ocamlfind ocamlc" --infer --base parser parser.mly ocamlfind ocamlc -c parser.mli ocamlfind ocamlopt -c parser.ml lexer.ml: lexer.mll ocamllex lexer.mll clean: @rm hb *.o *.cmi *.cmx lexer.ml parser.ml parser.mli 2>/dev/null || true
and here's making / running it, test.in first 1 above.
$ mk;hb < test.in ocamllex lexer.mll menhir --ocamlc "ocamlfind ocamlc" --infer --base parser parser.mly 15 states, 286 transitions, table size 1234 bytes warning: 3 states have shift/reduce conflicts. warning: 3 shift/reduce conflicts arbitrarily resolved. ocamlfind ocamlc -c parser.mli ocamlfind ocamlopt -c parser.ml ocamlfind ocamlopt -c lexer.ml ocamlfind ocamlopt -package core -package core_kernel -thread -w -10 \ -c interpreter.ml ocamlfind ocamlopt -o hb -linkpkg -package core -package core_kernel \ -thread -w -10 parser.cmx lexer.cmx interpreter.cmx syntax error @ offset 45. var foo var min qvar min var max qvar max var foo [var min ]qvar min
edit 2: ended adding | e = var lbrack v = q_var rbrack { getmap(v,lookupvar(e)) }
special case parser. so, problem solved?
i've tried play language, , agree parser, input bad, @ "assign map field" rule:
v = var lbrack f = q_var rbrack assign e = exp
if remove noisy variables (that don't need use, btw):
var lbrack q_var rbrack assign exp
that means rule expects:
var, '[' '"' var '"' ']' '=' exp
for example
foo["min"] = 42
the following accepted
{ foo = { "min" : 1 ,"max" : 5}; foo["min"] = 42 }