xref: /aosp_15_r20/external/llvm/examples/OCaml-Kaleidoscope/Chapter4/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 Workerlet rec parse_primary = parser
17*9880d681SAndroid Build Coastguard Worker  (* numberexpr ::= number *)
18*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Number n >] -> Ast.Number n
19*9880d681SAndroid Build Coastguard Worker
20*9880d681SAndroid Build Coastguard Worker  (* parenexpr ::= '(' expression ')' *)
21*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e
22*9880d681SAndroid Build Coastguard Worker
23*9880d681SAndroid Build Coastguard Worker  (* identifierexpr
24*9880d681SAndroid Build Coastguard Worker   *   ::= identifier
25*9880d681SAndroid Build Coastguard Worker   *   ::= identifier '(' argumentexpr ')' *)
26*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Ident id; stream >] ->
27*9880d681SAndroid Build Coastguard Worker      let rec parse_args accumulator = parser
28*9880d681SAndroid Build Coastguard Worker        | [< e=parse_expr; stream >] ->
29*9880d681SAndroid Build Coastguard Worker            begin parser
30*9880d681SAndroid Build Coastguard Worker              | [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e
31*9880d681SAndroid Build Coastguard Worker              | [< >] -> e :: accumulator
32*9880d681SAndroid Build Coastguard Worker            end stream
33*9880d681SAndroid Build Coastguard Worker        | [< >] -> accumulator
34*9880d681SAndroid Build Coastguard Worker      in
35*9880d681SAndroid Build Coastguard Worker      let rec parse_ident id = parser
36*9880d681SAndroid Build Coastguard Worker        (* Call. *)
37*9880d681SAndroid Build Coastguard Worker        | [< 'Token.Kwd '(';
38*9880d681SAndroid Build Coastguard Worker             args=parse_args [];
39*9880d681SAndroid Build Coastguard Worker             'Token.Kwd ')' ?? "expected ')'">] ->
40*9880d681SAndroid Build Coastguard Worker            Ast.Call (id, Array.of_list (List.rev args))
41*9880d681SAndroid Build Coastguard Worker
42*9880d681SAndroid Build Coastguard Worker        (* Simple variable ref. *)
43*9880d681SAndroid Build Coastguard Worker        | [< >] -> Ast.Variable id
44*9880d681SAndroid Build Coastguard Worker      in
45*9880d681SAndroid Build Coastguard Worker      parse_ident id stream
46*9880d681SAndroid Build Coastguard Worker
47*9880d681SAndroid Build Coastguard Worker  | [< >] -> raise (Stream.Error "unknown token when expecting an expression.")
48*9880d681SAndroid Build Coastguard Worker
49*9880d681SAndroid Build Coastguard Worker(* binoprhs
50*9880d681SAndroid Build Coastguard Worker *   ::= ('+' primary)* *)
51*9880d681SAndroid Build Coastguard Workerand parse_bin_rhs expr_prec lhs stream =
52*9880d681SAndroid Build Coastguard Worker  match Stream.peek stream with
53*9880d681SAndroid Build Coastguard Worker  (* If this is a binop, find its precedence. *)
54*9880d681SAndroid Build Coastguard Worker  | Some (Token.Kwd c) when Hashtbl.mem binop_precedence c ->
55*9880d681SAndroid Build Coastguard Worker      let token_prec = precedence c in
56*9880d681SAndroid Build Coastguard Worker
57*9880d681SAndroid Build Coastguard Worker      (* If this is a binop that binds at least as tightly as the current binop,
58*9880d681SAndroid Build Coastguard Worker       * consume it, otherwise we are done. *)
59*9880d681SAndroid Build Coastguard Worker      if token_prec < expr_prec then lhs else begin
60*9880d681SAndroid Build Coastguard Worker        (* Eat the binop. *)
61*9880d681SAndroid Build Coastguard Worker        Stream.junk stream;
62*9880d681SAndroid Build Coastguard Worker
63*9880d681SAndroid Build Coastguard Worker        (* Parse the primary expression after the binary operator. *)
64*9880d681SAndroid Build Coastguard Worker        let rhs = parse_primary stream in
65*9880d681SAndroid Build Coastguard Worker
66*9880d681SAndroid Build Coastguard Worker        (* Okay, we know this is a binop. *)
67*9880d681SAndroid Build Coastguard Worker        let rhs =
68*9880d681SAndroid Build Coastguard Worker          match Stream.peek stream with
69*9880d681SAndroid Build Coastguard Worker          | Some (Token.Kwd c2) ->
70*9880d681SAndroid Build Coastguard Worker              (* If BinOp binds less tightly with rhs than the operator after
71*9880d681SAndroid Build Coastguard Worker               * rhs, let the pending operator take rhs as its lhs. *)
72*9880d681SAndroid Build Coastguard Worker              let next_prec = precedence c2 in
73*9880d681SAndroid Build Coastguard Worker              if token_prec < next_prec
74*9880d681SAndroid Build Coastguard Worker              then parse_bin_rhs (token_prec + 1) rhs stream
75*9880d681SAndroid Build Coastguard Worker              else rhs
76*9880d681SAndroid Build Coastguard Worker          | _ -> rhs
77*9880d681SAndroid Build Coastguard Worker        in
78*9880d681SAndroid Build Coastguard Worker
79*9880d681SAndroid Build Coastguard Worker        (* Merge lhs/rhs. *)
80*9880d681SAndroid Build Coastguard Worker        let lhs = Ast.Binary (c, lhs, rhs) in
81*9880d681SAndroid Build Coastguard Worker        parse_bin_rhs expr_prec lhs stream
82*9880d681SAndroid Build Coastguard Worker      end
83*9880d681SAndroid Build Coastguard Worker  | _ -> lhs
84*9880d681SAndroid Build Coastguard Worker
85*9880d681SAndroid Build Coastguard Worker(* expression
86*9880d681SAndroid Build Coastguard Worker *   ::= primary binoprhs *)
87*9880d681SAndroid Build Coastguard Workerand parse_expr = parser
88*9880d681SAndroid Build Coastguard Worker  | [< lhs=parse_primary; stream >] -> parse_bin_rhs 0 lhs stream
89*9880d681SAndroid Build Coastguard Worker
90*9880d681SAndroid Build Coastguard Worker(* prototype
91*9880d681SAndroid Build Coastguard Worker *   ::= id '(' id* ')' *)
92*9880d681SAndroid Build Coastguard Workerlet parse_prototype =
93*9880d681SAndroid Build Coastguard Worker  let rec parse_args accumulator = parser
94*9880d681SAndroid Build Coastguard Worker    | [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e
95*9880d681SAndroid Build Coastguard Worker    | [< >] -> accumulator
96*9880d681SAndroid Build Coastguard Worker  in
97*9880d681SAndroid Build Coastguard Worker
98*9880d681SAndroid Build Coastguard Worker  parser
99*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Ident id;
100*9880d681SAndroid Build Coastguard Worker       'Token.Kwd '(' ?? "expected '(' in prototype";
101*9880d681SAndroid Build Coastguard Worker       args=parse_args [];
102*9880d681SAndroid Build Coastguard Worker       'Token.Kwd ')' ?? "expected ')' in prototype" >] ->
103*9880d681SAndroid Build Coastguard Worker      (* success. *)
104*9880d681SAndroid Build Coastguard Worker      Ast.Prototype (id, Array.of_list (List.rev args))
105*9880d681SAndroid Build Coastguard Worker
106*9880d681SAndroid Build Coastguard Worker  | [< >] ->
107*9880d681SAndroid Build Coastguard Worker      raise (Stream.Error "expected function name in prototype")
108*9880d681SAndroid Build Coastguard Worker
109*9880d681SAndroid Build Coastguard Worker(* definition ::= 'def' prototype expression *)
110*9880d681SAndroid Build Coastguard Workerlet parse_definition = parser
111*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Def; p=parse_prototype; e=parse_expr >] ->
112*9880d681SAndroid Build Coastguard Worker      Ast.Function (p, e)
113*9880d681SAndroid Build Coastguard Worker
114*9880d681SAndroid Build Coastguard Worker(* toplevelexpr ::= expression *)
115*9880d681SAndroid Build Coastguard Workerlet parse_toplevel = parser
116*9880d681SAndroid Build Coastguard Worker  | [< e=parse_expr >] ->
117*9880d681SAndroid Build Coastguard Worker      (* Make an anonymous proto. *)
118*9880d681SAndroid Build Coastguard Worker      Ast.Function (Ast.Prototype ("", [||]), e)
119*9880d681SAndroid Build Coastguard Worker
120*9880d681SAndroid Build Coastguard Worker(*  external ::= 'extern' prototype *)
121*9880d681SAndroid Build Coastguard Workerlet parse_extern = parser
122*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Extern; e=parse_prototype >] -> e
123