parser.mly:
%{
let env=Hashtbl.create 10
%}
%token <int> INT
%token SUB
%token EOL
%token EQUAL
%token NAME
%left SUB EQUAL
%start main /* the entry point */
%type<int> main
%%
main:
expr EOL { $1 }
;
expr:
INT { $1}
| expr SUB expr { $1 - $3}
| var EQUAL expr {Hashtbl.add env $1 $3;0}
| var {Hashtbl.find env $1}
;
var:NAME {$1}
(the 12's line is: %type<int> main
)
using:
wangkai@wangkai-ThinkPad-X1:~/src/ocaml/lexonlysub$ ./calc
a=1
0
b=2
0
b
2
a
2
^C
I don't know why after define b=2,then a is 2 too,it should be 1.Why got 2?
and this:
wangkai@wangkai-ThinkPad-X1:~/src/ocaml/lexonlysub$ ./calc
a=1
0
b=2
0
a-b
0
lexer.mll:
{
open Parser
exception Eof
}
rule token = parse
[' ' '\t'] { token lexbuf } (* skip blanks *)
| ['\n' ] { EOL }
| ['0'-'9']+ as lxm { INT(int_of_string lxm) }
| '-' { SUB }
|['a'-'z']+ {NAME}
|'=' {EQUAL}
| eof { raise Eof }
Thanks!
calc.ml
open Syntax
let _ =
try
let lexbuf = Lexing.from_channel stdin in
while true do
let result = Parser.main Lexer.token lexbuf in
print_int result;
print_newline ();
flush stdout
done
with Lexer.Eof -> exit 0
makefile:
calc:lexer.cmo parser.cmo syntax.cmo calc.cmo ocamlc -o calc lexer.cmo parser.cmo syntax.cmo calc.cmo lexer.cmo:lexer.mll ocamllex lexer.mll parser.cmo:parser.mly menhir parser.mly syntax.cmo:syntax.ml ocamlc -c syntax.ml calc.cmo:calc.ml ocamlc -c lexer.ml ocamlc -c parser.mli ocamlc -c parser.ml ocamlc -c calc.ml
You need to add a payload to NAME
. Otherwise, it won't register the string that was lexed; instead, the value it gives you is just ()
, so every time you access your hash table you access the same element.
You need to add the string
type to NAME
:
%token<string> NAME
to have a string
payload. You also need to actually remember that payload in the lexer:
| ['a'-'z']+ as name { NAME(name) }
(these two snippets should replace their equivalent in your code)
You can ensure that you have the appropriate type by adding some annotations:
%{
let env : (string, int) Hashtbl.t = Hashtbl.create 10
%}
(if you add this annotation to your current version, it should fail; but it won't with the appropriate payload added to NAME
).