xref: /aosp_15_r20/external/llvm/examples/OCaml-Kaleidoscope/Chapter6/parser.ml (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker(*===---------------------------------------------------------------------===
2*9880d681SAndroid Build Coastguard Worker * Parser
3*9880d681SAndroid Build Coastguard Worker *===---------------------------------------------------------------------===*)
4*9880d681SAndroid Build Coastguard Worker
5*9880d681SAndroid Build Coastguard Worker(* binop_precedence - This holds the precedence for each binary operator that is
6*9880d681SAndroid Build Coastguard Worker * defined *)
7*9880d681SAndroid Build Coastguard Workerlet binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10
8*9880d681SAndroid Build Coastguard Worker
9*9880d681SAndroid Build Coastguard Worker(* precedence - Get the precedence of the pending binary operator token. *)
10*9880d681SAndroid Build Coastguard Workerlet precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1
11*9880d681SAndroid Build Coastguard Worker
12*9880d681SAndroid Build Coastguard Worker(* primary
13*9880d681SAndroid Build Coastguard Worker *   ::= identifier
14*9880d681SAndroid Build Coastguard Worker *   ::= numberexpr
15*9880d681SAndroid Build Coastguard Worker *   ::= parenexpr
16*9880d681SAndroid Build Coastguard Worker *   ::= ifexpr
17*9880d681SAndroid Build Coastguard Worker *   ::= forexpr *)
18*9880d681SAndroid Build Coastguard Workerlet rec parse_primary = parser
19*9880d681SAndroid Build Coastguard Worker  (* numberexpr ::= number *)
20*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Number n >] -> Ast.Number n
21*9880d681SAndroid Build Coastguard Worker
22*9880d681SAndroid Build Coastguard Worker  (* parenexpr ::= '(' expression ')' *)
23*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e
24*9880d681SAndroid Build Coastguard Worker
25*9880d681SAndroid Build Coastguard Worker  (* identifierexpr
26*9880d681SAndroid Build Coastguard Worker   *   ::= identifier
27*9880d681SAndroid Build Coastguard Worker   *   ::= identifier '(' argumentexpr ')' *)
28*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Ident id; stream >] ->
29*9880d681SAndroid Build Coastguard Worker      let rec parse_args accumulator = parser
30*9880d681SAndroid Build Coastguard Worker        | [< e=parse_expr; stream >] ->
31*9880d681SAndroid Build Coastguard Worker            begin parser
32*9880d681SAndroid Build Coastguard Worker              | [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e
33*9880d681SAndroid Build Coastguard Worker              | [< >] -> e :: accumulator
34*9880d681SAndroid Build Coastguard Worker            end stream
35*9880d681SAndroid Build Coastguard Worker        | [< >] -> accumulator
36*9880d681SAndroid Build Coastguard Worker      in
37*9880d681SAndroid Build Coastguard Worker      let rec parse_ident id = parser
38*9880d681SAndroid Build Coastguard Worker        (* Call. *)
39*9880d681SAndroid Build Coastguard Worker        | [< 'Token.Kwd '(';
40*9880d681SAndroid Build Coastguard Worker             args=parse_args [];
41*9880d681SAndroid Build Coastguard Worker             'Token.Kwd ')' ?? "expected ')'">] ->
42*9880d681SAndroid Build Coastguard Worker            Ast.Call (id, Array.of_list (List.rev args))
43*9880d681SAndroid Build Coastguard Worker
44*9880d681SAndroid Build Coastguard Worker        (* Simple variable ref. *)
45*9880d681SAndroid Build Coastguard Worker        | [< >] -> Ast.Variable id
46*9880d681SAndroid Build Coastguard Worker      in
47*9880d681SAndroid Build Coastguard Worker      parse_ident id stream
48*9880d681SAndroid Build Coastguard Worker
49*9880d681SAndroid Build Coastguard Worker  (* ifexpr ::= 'if' expr 'then' expr 'else' expr *)
50*9880d681SAndroid Build Coastguard Worker  | [< 'Token.If; c=parse_expr;
51*9880d681SAndroid Build Coastguard Worker       'Token.Then ?? "expected 'then'"; t=parse_expr;
52*9880d681SAndroid Build Coastguard Worker       'Token.Else ?? "expected 'else'"; e=parse_expr >] ->
53*9880d681SAndroid Build Coastguard Worker      Ast.If (c, t, e)
54*9880d681SAndroid Build Coastguard Worker
55*9880d681SAndroid Build Coastguard Worker  (* forexpr
56*9880d681SAndroid Build Coastguard Worker        ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression *)
57*9880d681SAndroid Build Coastguard Worker  | [< 'Token.For;
58*9880d681SAndroid Build Coastguard Worker       'Token.Ident id ?? "expected identifier after for";
59*9880d681SAndroid Build Coastguard Worker       'Token.Kwd '=' ?? "expected '=' after for";
60*9880d681SAndroid Build Coastguard Worker       stream >] ->
61*9880d681SAndroid Build Coastguard Worker      begin parser
62*9880d681SAndroid Build Coastguard Worker        | [<
63*9880d681SAndroid Build Coastguard Worker             start=parse_expr;
64*9880d681SAndroid Build Coastguard Worker             'Token.Kwd ',' ?? "expected ',' after for";
65*9880d681SAndroid Build Coastguard Worker             end_=parse_expr;
66*9880d681SAndroid Build Coastguard Worker             stream >] ->
67*9880d681SAndroid Build Coastguard Worker            let step =
68*9880d681SAndroid Build Coastguard Worker              begin parser
69*9880d681SAndroid Build Coastguard Worker              | [< 'Token.Kwd ','; step=parse_expr >] -> Some step
70*9880d681SAndroid Build Coastguard Worker              | [< >] -> None
71*9880d681SAndroid Build Coastguard Worker              end stream
72*9880d681SAndroid Build Coastguard Worker            in
73*9880d681SAndroid Build Coastguard Worker            begin parser
74*9880d681SAndroid Build Coastguard Worker            | [< 'Token.In; body=parse_expr >] ->
75*9880d681SAndroid Build Coastguard Worker                Ast.For (id, start, end_, step, body)
76*9880d681SAndroid Build Coastguard Worker            | [< >] ->
77*9880d681SAndroid Build Coastguard Worker                raise (Stream.Error "expected 'in' after for")
78*9880d681SAndroid Build Coastguard Worker            end stream
79*9880d681SAndroid Build Coastguard Worker        | [< >] ->
80*9880d681SAndroid Build Coastguard Worker            raise (Stream.Error "expected '=' after for")
81*9880d681SAndroid Build Coastguard Worker      end stream
82*9880d681SAndroid Build Coastguard Worker
83*9880d681SAndroid Build Coastguard Worker  | [< >] -> raise (Stream.Error "unknown token when expecting an expression.")
84*9880d681SAndroid Build Coastguard Worker
85*9880d681SAndroid Build Coastguard Worker(* unary
86*9880d681SAndroid Build Coastguard Worker *   ::= primary
87*9880d681SAndroid Build Coastguard Worker *   ::= '!' unary *)
88*9880d681SAndroid Build Coastguard Workerand parse_unary = parser
89*9880d681SAndroid Build Coastguard Worker  (* If this is a unary operator, read it. *)
90*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Kwd op when op != '(' && op != ')'; operand=parse_expr >] ->
91*9880d681SAndroid Build Coastguard Worker      Ast.Unary (op, operand)
92*9880d681SAndroid Build Coastguard Worker
93*9880d681SAndroid Build Coastguard Worker  (* If the current token is not an operator, it must be a primary expr. *)
94*9880d681SAndroid Build Coastguard Worker  | [< stream >] -> parse_primary stream
95*9880d681SAndroid Build Coastguard Worker
96*9880d681SAndroid Build Coastguard Worker(* binoprhs
97*9880d681SAndroid Build Coastguard Worker *   ::= ('+' primary)* *)
98*9880d681SAndroid Build Coastguard Workerand parse_bin_rhs expr_prec lhs stream =
99*9880d681SAndroid Build Coastguard Worker  match Stream.peek stream with
100*9880d681SAndroid Build Coastguard Worker  (* If this is a binop, find its precedence. *)
101*9880d681SAndroid Build Coastguard Worker  | Some (Token.Kwd c) when Hashtbl.mem binop_precedence c ->
102*9880d681SAndroid Build Coastguard Worker      let token_prec = precedence c in
103*9880d681SAndroid Build Coastguard Worker
104*9880d681SAndroid Build Coastguard Worker      (* If this is a binop that binds at least as tightly as the current binop,
105*9880d681SAndroid Build Coastguard Worker       * consume it, otherwise we are done. *)
106*9880d681SAndroid Build Coastguard Worker      if token_prec < expr_prec then lhs else begin
107*9880d681SAndroid Build Coastguard Worker        (* Eat the binop. *)
108*9880d681SAndroid Build Coastguard Worker        Stream.junk stream;
109*9880d681SAndroid Build Coastguard Worker
110*9880d681SAndroid Build Coastguard Worker        (* Parse the unary expression after the binary operator. *)
111*9880d681SAndroid Build Coastguard Worker        let rhs = parse_unary stream in
112*9880d681SAndroid Build Coastguard Worker
113*9880d681SAndroid Build Coastguard Worker        (* Okay, we know this is a binop. *)
114*9880d681SAndroid Build Coastguard Worker        let rhs =
115*9880d681SAndroid Build Coastguard Worker          match Stream.peek stream with
116*9880d681SAndroid Build Coastguard Worker          | Some (Token.Kwd c2) ->
117*9880d681SAndroid Build Coastguard Worker              (* If BinOp binds less tightly with rhs than the operator after
118*9880d681SAndroid Build Coastguard Worker               * rhs, let the pending operator take rhs as its lhs. *)
119*9880d681SAndroid Build Coastguard Worker              let next_prec = precedence c2 in
120*9880d681SAndroid Build Coastguard Worker              if token_prec < next_prec
121*9880d681SAndroid Build Coastguard Worker              then parse_bin_rhs (token_prec + 1) rhs stream
122*9880d681SAndroid Build Coastguard Worker              else rhs
123*9880d681SAndroid Build Coastguard Worker          | _ -> rhs
124*9880d681SAndroid Build Coastguard Worker        in
125*9880d681SAndroid Build Coastguard Worker
126*9880d681SAndroid Build Coastguard Worker        (* Merge lhs/rhs. *)
127*9880d681SAndroid Build Coastguard Worker        let lhs = Ast.Binary (c, lhs, rhs) in
128*9880d681SAndroid Build Coastguard Worker        parse_bin_rhs expr_prec lhs stream
129*9880d681SAndroid Build Coastguard Worker      end
130*9880d681SAndroid Build Coastguard Worker  | _ -> lhs
131*9880d681SAndroid Build Coastguard Worker
132*9880d681SAndroid Build Coastguard Worker(* expression
133*9880d681SAndroid Build Coastguard Worker *   ::= primary binoprhs *)
134*9880d681SAndroid Build Coastguard Workerand parse_expr = parser
135*9880d681SAndroid Build Coastguard Worker  | [< lhs=parse_unary; stream >] -> parse_bin_rhs 0 lhs stream
136*9880d681SAndroid Build Coastguard Worker
137*9880d681SAndroid Build Coastguard Worker(* prototype
138*9880d681SAndroid Build Coastguard Worker *   ::= id '(' id* ')'
139*9880d681SAndroid Build Coastguard Worker *   ::= binary LETTER number? (id, id)
140*9880d681SAndroid Build Coastguard Worker *   ::= unary LETTER number? (id) *)
141*9880d681SAndroid Build Coastguard Workerlet parse_prototype =
142*9880d681SAndroid Build Coastguard Worker  let rec parse_args accumulator = parser
143*9880d681SAndroid Build Coastguard Worker    | [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e
144*9880d681SAndroid Build Coastguard Worker    | [< >] -> accumulator
145*9880d681SAndroid Build Coastguard Worker  in
146*9880d681SAndroid Build Coastguard Worker  let parse_operator = parser
147*9880d681SAndroid Build Coastguard Worker    | [< 'Token.Unary >] -> "unary", 1
148*9880d681SAndroid Build Coastguard Worker    | [< 'Token.Binary >] -> "binary", 2
149*9880d681SAndroid Build Coastguard Worker  in
150*9880d681SAndroid Build Coastguard Worker  let parse_binary_precedence = parser
151*9880d681SAndroid Build Coastguard Worker    | [< 'Token.Number n >] -> int_of_float n
152*9880d681SAndroid Build Coastguard Worker    | [< >] -> 30
153*9880d681SAndroid Build Coastguard Worker  in
154*9880d681SAndroid Build Coastguard Worker  parser
155*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Ident id;
156*9880d681SAndroid Build Coastguard Worker       'Token.Kwd '(' ?? "expected '(' in prototype";
157*9880d681SAndroid Build Coastguard Worker       args=parse_args [];
158*9880d681SAndroid Build Coastguard Worker       'Token.Kwd ')' ?? "expected ')' in prototype" >] ->
159*9880d681SAndroid Build Coastguard Worker      (* success. *)
160*9880d681SAndroid Build Coastguard Worker      Ast.Prototype (id, Array.of_list (List.rev args))
161*9880d681SAndroid Build Coastguard Worker  | [< (prefix, kind)=parse_operator;
162*9880d681SAndroid Build Coastguard Worker       'Token.Kwd op ?? "expected an operator";
163*9880d681SAndroid Build Coastguard Worker       (* Read the precedence if present. *)
164*9880d681SAndroid Build Coastguard Worker       binary_precedence=parse_binary_precedence;
165*9880d681SAndroid Build Coastguard Worker       'Token.Kwd '(' ?? "expected '(' in prototype";
166*9880d681SAndroid Build Coastguard Worker        args=parse_args [];
167*9880d681SAndroid Build Coastguard Worker       'Token.Kwd ')' ?? "expected ')' in prototype" >] ->
168*9880d681SAndroid Build Coastguard Worker      let name = prefix ^ (String.make 1 op) in
169*9880d681SAndroid Build Coastguard Worker      let args = Array.of_list (List.rev args) in
170*9880d681SAndroid Build Coastguard Worker
171*9880d681SAndroid Build Coastguard Worker      (* Verify right number of arguments for operator. *)
172*9880d681SAndroid Build Coastguard Worker      if Array.length args != kind
173*9880d681SAndroid Build Coastguard Worker      then raise (Stream.Error "invalid number of operands for operator")
174*9880d681SAndroid Build Coastguard Worker      else
175*9880d681SAndroid Build Coastguard Worker        if kind == 1 then
176*9880d681SAndroid Build Coastguard Worker          Ast.Prototype (name, args)
177*9880d681SAndroid Build Coastguard Worker        else
178*9880d681SAndroid Build Coastguard Worker          Ast.BinOpPrototype (name, args, binary_precedence)
179*9880d681SAndroid Build Coastguard Worker  | [< >] ->
180*9880d681SAndroid Build Coastguard Worker      raise (Stream.Error "expected function name in prototype")
181*9880d681SAndroid Build Coastguard Worker
182*9880d681SAndroid Build Coastguard Worker(* definition ::= 'def' prototype expression *)
183*9880d681SAndroid Build Coastguard Workerlet parse_definition = parser
184*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Def; p=parse_prototype; e=parse_expr >] ->
185*9880d681SAndroid Build Coastguard Worker      Ast.Function (p, e)
186*9880d681SAndroid Build Coastguard Worker
187*9880d681SAndroid Build Coastguard Worker(* toplevelexpr ::= expression *)
188*9880d681SAndroid Build Coastguard Workerlet parse_toplevel = parser
189*9880d681SAndroid Build Coastguard Worker  | [< e=parse_expr >] ->
190*9880d681SAndroid Build Coastguard Worker      (* Make an anonymous proto. *)
191*9880d681SAndroid Build Coastguard Worker      Ast.Function (Ast.Prototype ("", [||]), e)
192*9880d681SAndroid Build Coastguard Worker
193*9880d681SAndroid Build Coastguard Worker(*  external ::= 'extern' prototype *)
194*9880d681SAndroid Build Coastguard Workerlet parse_extern = parser
195*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Extern; e=parse_prototype >] -> e
196