Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

User-defined binary operators

  • Loading branch information...
commit fe931e98f6996dc2d15d289c412d64c03d2a1dac 1 parent 0f50776
@steshaw authored
View
4 ocaml/kaleidoscope/ast.ml
@@ -25,7 +25,9 @@ type expr =
(* proto - This type represents the "prototype" for a function, which captures
* its name, and its argument names (thus implicitly the number of arguments the
* function takes). *)
-type proto = Prototype of string * string array
+type proto =
+ | Prototype of string * string array
+ | BinOpPrototype of string * string array * int
(* func - This type represents a function definition itself. *)
type func = Function of proto * expr
View
16 ocaml/kaleidoscope/build.sh
@@ -2,7 +2,15 @@
LLVM_OCAML_LIB=/Users/steshaw/.shelly/local/llvm-3.0/lib/ocaml
-ocamlbuild \
- -cflags -I,$LLVM_OCAML_LIB \
- -lflags -I,$LLVM_OCAML_LIB \
- "$@"
+Build() {
+ ocamlbuild \
+ -cflags -I,$LLVM_OCAML_LIB \
+ -lflags -I,$LLVM_OCAML_LIB \
+ "$@"
+}
+
+if [[ $# -eq 0 ]]; then
+ Build toy.native
+else
+ Build "$@"
+fi
View
22 ocaml/kaleidoscope/codegen.ml
@@ -29,7 +29,16 @@ let rec codegen_expr = function
(* Convert bool 0/1 to double 0.0 or 1.0 *)
let i = build_fcmp Fcmp.Ult lhs_val rhs_val "cmptmp" builder in
build_uitofp i double_type "booltmp" builder
- | _ -> raise (Error "invalid binary operator")
+ | _ ->
+ (* If it wasn't a builtin binary operator, it must be a user-defined
+ * one. Emit a call to it. *)
+ let callee = "binary" ^ (String.make 1 op) in
+ let callee =
+ match lookup_function callee the_module with
+ | Some callee -> callee
+ | None -> raise (Error "binary operator not found!")
+ in
+ build_call callee [|lhs_val; rhs_val|] "binop" builder
end
| Ast.Call (callee, args) ->
(* Look up the name in the module table. *)
@@ -169,7 +178,8 @@ let rec codegen_expr = function
const_null double_type
let codegen_proto = function
- | Ast.Prototype (name, args) ->
+ | Ast.Prototype (name, args)
+ | Ast.BinOpPrototype (name, args, _) ->
(* Make the function type: double(double,double) etc. *)
let doubles = Array.make (Array.length args) double_type in
let ft = function_type double_type doubles in
@@ -203,6 +213,14 @@ let codegen_func the_fpm = function
Hashtbl.clear named_values;
let the_function = codegen_proto proto in
+ (* If this is an operator, install it. *)
+ begin match proto with
+ | Ast.BinOpPrototype (name, args, prec) ->
+ let op = name.[String.length name - 1] in
+ Hashtbl.add Parser.binop_precedence op prec;
+ | _ -> ()
+ end;
+
(* Create a new basic block to start insertion into. *)
let bb = append_block context "entry" the_function in
position_at_end bb builder;
View
0  ocaml/kaleidoscope/fib.kaleidoscope → ocaml/kaleidoscope/fib.ks
File renamed without changes
View
2  ocaml/kaleidoscope/lexer.ml
@@ -49,6 +49,8 @@ and lex_ident buffer = parser
| "else" -> [< 'Token.Else; stream >]
| "for" -> [< 'Token.For; stream >]
| "in" -> [< 'Token.In; stream >]
+ | "binary" -> [< 'Token.Binary; stream >]
+ | "unary" -> [< 'Token.Unary; stream >]
| id -> [< 'Token.Ident id; stream >]
and lex_comment = parser
View
33 ocaml/kaleidoscope/parser.ml
@@ -124,13 +124,23 @@ and parse_expr = parser
| [< lhs=parse_primary; stream >] -> parse_bin_rhs 0 lhs stream
(* prototype
- * ::= id '(' id* ')' *)
+ * ::= id '(' id* ')'
+ * ::= binary LETTER number? '(' id, id ')'
+ * ::= unary LETTER number? '(' id ')'
+ *)
let parse_prototype =
let rec parse_args accumulator = parser
| [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e
| [< >] -> accumulator
in
-
+ let parse_operator = parser
+ | [< 'Token.Unary >] -> "unary", 1
+ | [< 'Token.Binary >] -> "binary", 2
+ in
+ let parse_binary_precedence = parser
+ | [< 'Token.Number n >] -> int_of_float n
+ | [< >] -> 30
+ in
parser
| [< 'Token.Ident id;
'Token.Kwd '(' ?? "expected '(' in prototype";
@@ -139,6 +149,25 @@ let parse_prototype =
(* success. *)
Ast.Prototype (id, Array.of_list (List.rev args))
+ | [< (prefix, kind)=parse_operator;
+ 'Token.Kwd op ?? "expected an operator";
+ (* Read the precedence if present. *)
+ binary_precedence=parse_binary_precedence;
+ 'Token.Kwd '(' ?? "expected '(' in prototype";
+ args=parse_args [];
+ 'Token.Kwd ')' ?? "expected ')' in prototype" >] ->
+ let name = prefix ^ (String.make 1 op) in
+ let args = Array.of_list (List.rev args) in
+
+ (* Verify right number of arguments for operator. *)
+ if Array.length args != kind
+ then raise (Stream.Error "invalid number of operands for operator")
+ else
+ if kind == 1 then
+ Ast.Prototype (name, args)
+ else
+ Ast.BinOpPrototype (name, args, binary_precedence)
+
| [< >] ->
raise (Stream.Error "expected function name in prototype")
View
3  ocaml/kaleidoscope/token.ml
@@ -17,3 +17,6 @@ type token =
(* control *)
| If | Then | Else
| For | In
+
+ (* operators *)
+ | Binary | Unary
Please sign in to comment.
Something went wrong with that request. Please try again.