Add OCaml tutorial to the examples.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@97966 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Erick Tryzelaar 2010-03-08 19:32:27 +00:00
parent 9ef76b9985
commit 49457b8158
65 changed files with 3508 additions and 29 deletions

View File

@ -66,35 +66,64 @@ Archive.CMA := $(strip $(OCAMLC) -a -custom $(OCAMLAFLAGS) $(OCAMLDEBUGFLAG) \
Compile.CMX := $(strip $(OCAMLOPT) -c $(OCAMLCFLAGS) $(OCAMLDEBUGFLAG) -o)
Archive.CMXA := $(strip $(OCAMLOPT) -a $(OCAMLAFLAGS) $(OCAMLDEBUGFLAG) -o)
ifdef OCAMLOPT
Archive.EXE := $(strip $(OCAMLOPT) -cc $(CXX) $(OCAMLCFLAGS) $(UsedOcamLibs:%=%.cmxa) $(OCAMLDEBUGFLAG) -o)
else
Archive.EXE := $(strip $(OCAMLC) -cc $(CXX) $(OCAMLCFLAGS) $(OCAMLDEBUGFLAG:%=%.cma) -o)
endif
# Source files
OcamlSources1 := $(sort $(wildcard $(PROJ_SRC_DIR)/*.ml))
OcamlHeaders1 := $(OcamlSources1:.ml=.mli)
OcamlHeaders1 := $(sort $(wildcard $(PROJ_SRC_DIR)/*.mli))
OcamlSources := $(OcamlSources1:$(PROJ_SRC_DIR)/%=$(ObjDir)/%)
OcamlHeaders := $(OcamlHeaders1:$(PROJ_SRC_DIR)/%=$(ObjDir)/%)
OcamlSources2 := $(filter-out $(ExcludeSources),$(OcamlSources1))
OcamlHeaders2 := $(filter-out $(ExcludeHeaders),$(OcamlHeaders1))
OcamlSources := $(OcamlSources2:$(PROJ_SRC_DIR)/%=$(ObjDir)/%)
OcamlHeaders := $(OcamlHeaders2:$(PROJ_SRC_DIR)/%=$(ObjDir)/%)
# Intermediate files
LibraryCMA := $(ObjDir)/$(LIBRARYNAME).cma
LibraryCMXA := $(ObjDir)/$(LIBRARYNAME).cmxa
ObjectsCMI := $(OcamlSources:%.ml=%.cmi)
ObjectsCMO := $(OcamlSources:%.ml=%.cmo)
ObjectsCMX := $(OcamlSources:%.ml=%.cmx)
ifdef LIBRARYNAME
LibraryCMA := $(ObjDir)/$(LIBRARYNAME).cma
LibraryCMXA := $(ObjDir)/$(LIBRARYNAME).cmxa
endif
ifdef TOOLNAME
ToolEXE := $(ObjDir)/$(TOOLNAME)$(EXEEXT)
endif
# Output files
# The .cmo files are the only intermediates; all others are to be installed.
LibraryA := $(OcamlDir)/lib$(LIBRARYNAME).a
OutputCMA := $(LibraryCMA:$(ObjDir)/%.cma=$(OcamlDir)/%.cma)
OutputCMXA := $(LibraryCMXA:$(ObjDir)/%.cmxa=$(OcamlDir)/%.cmxa)
OutputsCMI := $(ObjectsCMI:$(ObjDir)/%.cmi=$(OcamlDir)/%.cmi)
OutputsCMX := $(ObjectsCMX:$(ObjDir)/%.cmx=$(OcamlDir)/%.cmx)
OutputLibs := $(UsedLibNames:%=$(OcamlDir)/%)
ifdef LIBRARYNAME
LibraryA := $(OcamlDir)/lib$(LIBRARYNAME).a
OutputCMA := $(LibraryCMA:$(ObjDir)/%.cma=$(OcamlDir)/%.cma)
OutputCMXA := $(LibraryCMXA:$(ObjDir)/%.cmxa=$(OcamlDir)/%.cmxa)
endif
ifdef TOOLNAME
ifdef EXAMPLE_TOOL
OutputEXE := $(ExmplDir)/$(strip $(TOOLNAME))$(EXEEXT)
else
OutputEXE := $(ToolDir)/$(strip $(TOOLNAME))$(EXEEXT)
endif
endif
# Installation targets
DestLibs := $(UsedLibNames:%=$(PROJ_libocamldir)/%)
ifdef LIBRARYNAME
DestA := $(PROJ_libocamldir)/lib$(LIBRARYNAME).a
DestCMA := $(PROJ_libocamldir)/$(LIBRARYNAME).cma
DestCMXA := $(PROJ_libocamldir)/$(LIBRARYNAME).cmxa
DestLibs := $(UsedLibNames:%=$(PROJ_libocamldir)/%)
endif
##===- Dependencies -------------------------------------------------------===##
# Copy the sources into the intermediate directory because older ocamlc doesn't
@ -106,18 +135,27 @@ $(ObjDir)/%.mli: $(PROJ_SRC_DIR)/%.mli $(ObjDir)/.dir
$(ObjDir)/%.ml: $(PROJ_SRC_DIR)/%.ml $(ObjDir)/.dir
$(Verb) $(CP) -f $< $@
$(ObjectsCMI): $(UsedOcamlInterfaces:%=$(OcamlDir)/%.cmi)
ifdef LIBRARYNAME
$(ObjDir)/$(LIBRARYNAME).ocamldep: $(OcamlSources) $(OcamlHeaders) \
$(OcamlDir)/.dir $(ObjDir)/.dir
$(Verb) $(OCAMLDEP) $(OCAMLCFLAGS) $(OcamlSources) $(OcamlHeaders) > $@
$(ObjectsCMI): $(UsedOcamlInterfaces:%=$(OcamlDir)/%.cmi)
-include $(ObjDir)/$(LIBRARYNAME).ocamldep
endif
ifdef TOOLNAME
$(ObjDir)/$(TOOLNAME).ocamldep: $(OcamlSources) $(OcamlHeaders) \
$(OcamlDir)/.dir $(ObjDir)/.dir
$(Verb) $(OCAMLDEP) $(OCAMLCFLAGS) $(OcamlSources) $(OcamlHeaders) > $@
-include $(ObjDir)/$(TOOLNAME).ocamldep
endif
##===- Build static library from C sources --------------------------------===##
ifneq ($(ObjectsO),)
ifdef LibraryA
all-local:: $(LibraryA)
clean-local:: clean-a
install-local:: install-a
@ -160,7 +198,7 @@ $(OcamlDir)/%.o: $(LibDir)/%.o
$(Verb) ln -sf $< $@
clean-deplibs:
$(Verb) rm -f $(OutputLibs)
$(Verb) $(RM) -f $(OutputLibs)
install-deplibs:
$(Verb) $(MKDIR) $(PROJ_libocamldir)
@ -169,11 +207,12 @@ install-deplibs:
done
uninstall-deplibs:
$(Verb) rm -f $(DestLibs)
$(Verb) $(RM) -f $(DestLibs)
##===- Build ocaml interfaces (.mli's -> .cmi's) --------------------------===##
ifneq ($(OcamlHeaders),)
all-local:: build-cmis
clean-local:: clean-cmis
install-local:: install-cmis
@ -212,10 +251,16 @@ uninstall-cmis::
$(EchoCmd) "Uninstalling $(PROJ_libocamldir)/$$i"; \
$(RM) -f "$(PROJ_libocamldir)/$$i"; \
done
endif
##===- Build ocaml bytecode archive (.ml's -> .cmo's -> .cma) -------------===##
$(ObjDir)/%.cmo: $(ObjDir)/%.ml
$(Echo) "Compiling $(notdir $<) for $(BuildMode) build"
$(Verb) $(Compile.CMO) $@ $<
ifdef LIBRARYNAME
all-local:: $(OutputCMA)
clean-local:: clean-cma
install-local:: install-cma
@ -228,10 +273,6 @@ $(LibraryCMA): $(ObjectsCMO) $(OcamlDir)/.dir
$(Echo) "Archiving $(notdir $@) for $(BuildMode) build"
$(Verb) $(Archive.CMA) $@ $(ObjectsCMO)
$(ObjDir)/%.cmo: $(ObjDir)/%.ml
$(Echo) "Compiling $(notdir $<) for $(BuildMode) build"
$(Verb) $(Compile.CMO) $@ $<
clean-cma::
$(Verb) $(RM) -f $(OutputCMA) $(UsedLibNames:%=$(OcamlDir)/%)
@ -243,7 +284,7 @@ install-cma:: $(OutputCMA)
uninstall-cma::
$(Echo) "Uninstalling $(DestCMA)"
-$(Verb) $(RM) -f $(DestCMA)
endif
##===- Build optimized ocaml archive (.ml's -> .cmx's -> .cmxa, .a) -------===##
@ -251,6 +292,14 @@ uninstall-cma::
# If unavailable, 'configure' will not define OCAMLOPT in Makefile.config.
ifdef OCAMLOPT
$(OcamlDir)/%.cmx: $(ObjDir)/%.cmx
$(Verb) $(CP) -f $< $@
$(ObjDir)/%.cmx: $(ObjDir)/%.ml
$(Echo) "Compiling optimized $(notdir $<) for $(BuildMode) build"
$(Verb) $(Compile.CMX) $@ $<
ifdef LIBRARYNAME
all-local:: $(OutputCMXA) $(OutputsCMX)
clean-local:: clean-cmxa
install-local:: install-cmxa
@ -260,18 +309,11 @@ $(OutputCMXA): $(LibraryCMXA)
$(Verb) $(CP) -f $< $@
$(Verb) $(CP) -f $(<:.cmxa=.a) $(@:.cmxa=.a)
$(OcamlDir)/%.cmx: $(ObjDir)/%.cmx
$(Verb) $(CP) -f $< $@
$(LibraryCMXA): $(ObjectsCMX)
$(Echo) "Archiving $(notdir $@) for $(BuildMode) build"
$(Verb) $(Archive.CMXA) $@ $(ObjectsCMX)
$(Verb) $(RM) -f $(@:.cmxa=.o)
$(ObjDir)/%.cmx: $(ObjDir)/%.ml
$(Echo) "Compiling optimized $(notdir $<) for $(BuildMode) build"
$(Verb) $(Compile.CMX) $@ $<
clean-cmxa::
$(Verb) $(RM) -f $(OutputCMXA) $(OutputCMXA:.cmxa=.a) $(OutputsCMX)
@ -295,7 +337,27 @@ uninstall-cmxa::
$(EchoCmd) "Uninstalling $(PROJ_libocamldir)/$$i"; \
$(RM) -f $(PROJ_libocamldir)/$$i; \
done
endif
endif
##===- Build executables --------------------------------------------------===##
ifdef TOOLNAME
all-local:: $(OutputEXE)
clean-local:: clean-exe
$(OutputEXE): $(ToolEXE) $(OcamlDir)/.dir
$(Verb) $(CP) -f $< $@
ifndef OCAMLOPT
$(ToolEXE): $(ObjectsCMO) $(OcamlDir)/.dir
$(Echo) "Archiving $(notdir $@) for $(BuildMode) build"
$(Verb) $(Archive.EXE) $@ $<
else
$(ToolEXE): $(ObjectsCMX) $(OcamlDir)/.dir
$(Echo) "Archiving $(notdir $@) for $(BuildMode) build"
$(Verb) $(Archive.EXE) $@ $<
endif
endif
##===- Generate documentation ---------------------------------------------===##
@ -325,7 +387,10 @@ printcamlvars::
$(Echo) "LibraryCMA : " '$(LibraryCMA)'
$(Echo) "LibraryCMXA : " '$(LibraryCMXA)'
$(Echo) "OcamlSources1: " '$(OcamlSources1)'
$(Echo) "OcamlSources2: " '$(OcamlSources2)'
$(Echo) "OcamlSources : " '$(OcamlSources)'
$(Echo) "OcamlHeaders1: " '$(OcamlHeaders1)'
$(Echo) "OcamlHeaders2: " '$(OcamlHeaders2)'
$(Echo) "OcamlHeaders : " '$(OcamlHeaders)'
$(Echo) "ObjectsCMI : " '$(ObjectsCMI)'
$(Echo) "ObjectsCMO : " '$(ObjectsCMO)'
@ -340,4 +405,6 @@ printcamlvars::
.PHONY: printcamlvars build-cmis \
clean-a clean-cmis clean-cma clean-cmxa \
install-a install-cmis install-cma install-cmxa \
uninstall-a uninstall-cmis uninstall-cma uninstall-cmxa
install-exe \
uninstall-a uninstall-cmis uninstall-cma uninstall-cmxa \
uninstall-exe

View File

@ -10,7 +10,8 @@ LEVEL=..
include $(LEVEL)/Makefile.config
PARALLEL_DIRS:= BrainF Fibonacci HowToUseJIT Kaleidoscope ModuleMaker
PARALLEL_DIRS:= BrainF Fibonacci HowToUseJIT Kaleidoscope ModuleMaker \
OCaml-Kaleidoscope
ifeq ($(HAVE_PTHREAD),1)
PARALLEL_DIRS += ParallelJIT

View File

@ -0,0 +1,22 @@
##===- examples/OCaml-Kaleidoscope/Chapter2/Makefile -------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
#
# This is the makefile for the Objective Caml kaleidoscope tutorial, chapter 2.
#
##===----------------------------------------------------------------------===##
LEVEL := ../../..
TOOLNAME := OCaml-Kaleidoscope-Ch2
EXAMPLE_TOOL := 1
UsedComponents := core
UsedOcamLibs := llvm
OCAMLCFLAGS += -pp camlp4of
include $(LEVEL)/bindings/ocaml/Makefile.ocaml

View File

@ -0,0 +1 @@
<{lexer,parser}.ml>: use_camlp4, pp(camlp4of)

View File

@ -0,0 +1,25 @@
(*===----------------------------------------------------------------------===
* Abstract Syntax Tree (aka Parse Tree)
*===----------------------------------------------------------------------===*)
(* expr - Base type for all expression nodes. *)
type expr =
(* variant for numeric literals like "1.0". *)
| Number of float
(* variant for referencing a variable, like "a". *)
| Variable of string
(* variant for a binary operator. *)
| Binary of char * expr * expr
(* variant for function calls. *)
| Call of string * expr array
(* 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
(* func - This type represents a function definition itself. *)
type func = Function of proto * expr

View File

@ -0,0 +1,52 @@
(*===----------------------------------------------------------------------===
* Lexer
*===----------------------------------------------------------------------===*)
let rec lex = parser
(* Skip any whitespace. *)
| [< ' (' ' | '\n' | '\r' | '\t'); stream >] -> lex stream
(* identifier: [a-zA-Z][a-zA-Z0-9] *)
| [< ' ('A' .. 'Z' | 'a' .. 'z' as c); stream >] ->
let buffer = Buffer.create 1 in
Buffer.add_char buffer c;
lex_ident buffer stream
(* number: [0-9.]+ *)
| [< ' ('0' .. '9' as c); stream >] ->
let buffer = Buffer.create 1 in
Buffer.add_char buffer c;
lex_number buffer stream
(* Comment until end of line. *)
| [< ' ('#'); stream >] ->
lex_comment stream
(* Otherwise, just return the character as its ascii value. *)
| [< 'c; stream >] ->
[< 'Token.Kwd c; lex stream >]
(* end of stream. *)
| [< >] -> [< >]
and lex_number buffer = parser
| [< ' ('0' .. '9' | '.' as c); stream >] ->
Buffer.add_char buffer c;
lex_number buffer stream
| [< stream=lex >] ->
[< 'Token.Number (float_of_string (Buffer.contents buffer)); stream >]
and lex_ident buffer = parser
| [< ' ('A' .. 'Z' | 'a' .. 'z' | '0' .. '9' as c); stream >] ->
Buffer.add_char buffer c;
lex_ident buffer stream
| [< stream=lex >] ->
match Buffer.contents buffer with
| "def" -> [< 'Token.Def; stream >]
| "extern" -> [< 'Token.Extern; stream >]
| id -> [< 'Token.Ident id; stream >]
and lex_comment = parser
| [< ' ('\n'); stream=lex >] -> stream
| [< 'c; e=lex_comment >] -> e
| [< >] -> [< >]

View File

@ -0,0 +1,122 @@
(*===---------------------------------------------------------------------===
* Parser
*===---------------------------------------------------------------------===*)
(* binop_precedence - This holds the precedence for each binary operator that is
* defined *)
let binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10
(* precedence - Get the precedence of the pending binary operator token. *)
let precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1
(* primary
* ::= identifier
* ::= numberexpr
* ::= parenexpr *)
let rec parse_primary = parser
(* numberexpr ::= number *)
| [< 'Token.Number n >] -> Ast.Number n
(* parenexpr ::= '(' expression ')' *)
| [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e
(* identifierexpr
* ::= identifier
* ::= identifier '(' argumentexpr ')' *)
| [< 'Token.Ident id; stream >] ->
let rec parse_args accumulator = parser
| [< e=parse_expr; stream >] ->
begin parser
| [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e
| [< >] -> e :: accumulator
end stream
| [< >] -> accumulator
in
let rec parse_ident id = parser
(* Call. *)
| [< 'Token.Kwd '(';
args=parse_args [];
'Token.Kwd ')' ?? "expected ')'">] ->
Ast.Call (id, Array.of_list (List.rev args))
(* Simple variable ref. *)
| [< >] -> Ast.Variable id
in
parse_ident id stream
| [< >] -> raise (Stream.Error "unknown token when expecting an expression.")
(* binoprhs
* ::= ('+' primary)* *)
and parse_bin_rhs expr_prec lhs stream =
match Stream.peek stream with
(* If this is a binop, find its precedence. *)
| Some (Token.Kwd c) when Hashtbl.mem binop_precedence c ->
let token_prec = precedence c in
(* If this is a binop that binds at least as tightly as the current binop,
* consume it, otherwise we are done. *)
if token_prec < expr_prec then lhs else begin
(* Eat the binop. *)
Stream.junk stream;
(* Parse the primary expression after the binary operator. *)
let rhs = parse_primary stream in
(* Okay, we know this is a binop. *)
let rhs =
match Stream.peek stream with
| Some (Token.Kwd c2) ->
(* If BinOp binds less tightly with rhs than the operator after
* rhs, let the pending operator take rhs as its lhs. *)
let next_prec = precedence c2 in
if token_prec < next_prec
then parse_bin_rhs (token_prec + 1) rhs stream
else rhs
| _ -> rhs
in
(* Merge lhs/rhs. *)
let lhs = Ast.Binary (c, lhs, rhs) in
parse_bin_rhs expr_prec lhs stream
end
| _ -> lhs
(* expression
* ::= primary binoprhs *)
and parse_expr = parser
| [< lhs=parse_primary; stream >] -> parse_bin_rhs 0 lhs stream
(* prototype
* ::= id '(' id* ')' *)
let parse_prototype =
let rec parse_args accumulator = parser
| [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e
| [< >] -> accumulator
in
parser
| [< 'Token.Ident id;
'Token.Kwd '(' ?? "expected '(' in prototype";
args=parse_args [];
'Token.Kwd ')' ?? "expected ')' in prototype" >] ->
(* success. *)
Ast.Prototype (id, Array.of_list (List.rev args))
| [< >] ->
raise (Stream.Error "expected function name in prototype")
(* definition ::= 'def' prototype expression *)
let parse_definition = parser
| [< 'Token.Def; p=parse_prototype; e=parse_expr >] ->
Ast.Function (p, e)
(* toplevelexpr ::= expression *)
let parse_toplevel = parser
| [< e=parse_expr >] ->
(* Make an anonymous proto. *)
Ast.Function (Ast.Prototype ("", [||]), e)
(* external ::= 'extern' prototype *)
let parse_extern = parser
| [< 'Token.Extern; e=parse_prototype >] -> e

View File

@ -0,0 +1,15 @@
(*===----------------------------------------------------------------------===
* Lexer Tokens
*===----------------------------------------------------------------------===*)
(* The lexer returns these 'Kwd' if it is an unknown character, otherwise one of
* these others for known things. *)
type token =
(* commands *)
| Def | Extern
(* primary *)
| Ident of string | Number of float
(* unknown *)
| Kwd of char

View File

@ -0,0 +1,34 @@
(*===----------------------------------------------------------------------===
* Top-Level parsing and JIT Driver
*===----------------------------------------------------------------------===*)
(* top ::= definition | external | expression | ';' *)
let rec main_loop stream =
match Stream.peek stream with
| None -> ()
(* ignore top-level semicolons. *)
| Some (Token.Kwd ';') ->
Stream.junk stream;
main_loop stream
| Some token ->
begin
try match token with
| Token.Def ->
ignore(Parser.parse_definition stream);
print_endline "parsed a function definition.";
| Token.Extern ->
ignore(Parser.parse_extern stream);
print_endline "parsed an extern.";
| _ ->
(* Evaluate a top-level expression into an anonymous function. *)
ignore(Parser.parse_toplevel stream);
print_endline "parsed a top-level expr";
with Stream.Error s ->
(* Skip token for error recovery. *)
Stream.junk stream;
print_endline s;
end;
print_string "ready> "; flush stdout;
main_loop stream

View File

@ -0,0 +1,21 @@
(*===----------------------------------------------------------------------===
* Main driver code.
*===----------------------------------------------------------------------===*)
let main () =
(* Install standard binary operators.
* 1 is the lowest precedence. *)
Hashtbl.add Parser.binop_precedence '<' 10;
Hashtbl.add Parser.binop_precedence '+' 20;
Hashtbl.add Parser.binop_precedence '-' 20;
Hashtbl.add Parser.binop_precedence '*' 40; (* highest. *)
(* Prime the first token. *)
print_string "ready> "; flush stdout;
let stream = Lexer.lex (Stream.of_channel stdin) in
(* Run the main "interpreter loop" now. *)
Toplevel.main_loop stream;
;;
main ()

View File

@ -0,0 +1,24 @@
##===- examples/OCaml-Kaleidoscope/Chapter3/Makefile -------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
#
# This is the makefile for the Objective Caml kaleidoscope tutorial, chapter 3.
#
##===----------------------------------------------------------------------===##
LEVEL := ../../..
TOOLNAME := OCaml-Kaleidoscope-Ch3
EXAMPLE_TOOL := 1
UsedComponents := core
UsedOcamLibs := llvm llvm_analysis
OCAMLCFLAGS += -pp camlp4of
ExcludeSources = $(PROJ_SRC_DIR)/myocamlbuild.ml
include $(LEVEL)/bindings/ocaml/Makefile.ocaml

View File

@ -0,0 +1,2 @@
<{lexer,parser}.ml>: use_camlp4, pp(camlp4of)
<*.{byte,native}>: g++, use_llvm, use_llvm_analysis

View File

@ -0,0 +1,25 @@
(*===----------------------------------------------------------------------===
* Abstract Syntax Tree (aka Parse Tree)
*===----------------------------------------------------------------------===*)
(* expr - Base type for all expression nodes. *)
type expr =
(* variant for numeric literals like "1.0". *)
| Number of float
(* variant for referencing a variable, like "a". *)
| Variable of string
(* variant for a binary operator. *)
| Binary of char * expr * expr
(* variant for function calls. *)
| Call of string * expr array
(* 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
(* func - This type represents a function definition itself. *)
type func = Function of proto * expr

View File

@ -0,0 +1,100 @@
(*===----------------------------------------------------------------------===
* Code Generation
*===----------------------------------------------------------------------===*)
open Llvm
exception Error of string
let context = global_context ()
let the_module = create_module context "my cool jit"
let builder = builder context
let named_values:(string, llvalue) Hashtbl.t = Hashtbl.create 10
let double_type = double_type context
let rec codegen_expr = function
| Ast.Number n -> const_float double_type n
| Ast.Variable name ->
(try Hashtbl.find named_values name with
| Not_found -> raise (Error "unknown variable name"))
| Ast.Binary (op, lhs, rhs) ->
let lhs_val = codegen_expr lhs in
let rhs_val = codegen_expr rhs in
begin
match op with
| '+' -> build_add lhs_val rhs_val "addtmp" builder
| '-' -> build_sub lhs_val rhs_val "subtmp" builder
| '*' -> build_mul lhs_val rhs_val "multmp" builder
| '<' ->
(* 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")
end
| Ast.Call (callee, args) ->
(* Look up the name in the module table. *)
let callee =
match lookup_function callee the_module with
| Some callee -> callee
| None -> raise (Error "unknown function referenced")
in
let params = params callee in
(* If argument mismatch error. *)
if Array.length params == Array.length args then () else
raise (Error "incorrect # arguments passed");
let args = Array.map codegen_expr args in
build_call callee args "calltmp" builder
let codegen_proto = function
| Ast.Prototype (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
let f =
match lookup_function name the_module with
| None -> declare_function name ft the_module
(* If 'f' conflicted, there was already something named 'name'. If it
* has a body, don't allow redefinition or reextern. *)
| Some f ->
(* If 'f' already has a body, reject this. *)
if block_begin f <> At_end f then
raise (Error "redefinition of function");
(* If 'f' took a different number of arguments, reject. *)
if element_type (type_of f) <> ft then
raise (Error "redefinition of function with different # args");
f
in
(* Set names for all arguments. *)
Array.iteri (fun i a ->
let n = args.(i) in
set_value_name n a;
Hashtbl.add named_values n a;
) (params f);
f
let codegen_func = function
| Ast.Function (proto, body) ->
Hashtbl.clear named_values;
let the_function = codegen_proto proto in
(* Create a new basic block to start insertion into. *)
let bb = append_block context "entry" the_function in
position_at_end bb builder;
try
let ret_val = codegen_expr body in
(* Finish off the function. *)
let _ = build_ret ret_val builder in
(* Validate the generated code, checking for consistency. *)
Llvm_analysis.assert_valid_function the_function;
the_function
with e ->
delete_function the_function;
raise e

View File

@ -0,0 +1,52 @@
(*===----------------------------------------------------------------------===
* Lexer
*===----------------------------------------------------------------------===*)
let rec lex = parser
(* Skip any whitespace. *)
| [< ' (' ' | '\n' | '\r' | '\t'); stream >] -> lex stream
(* identifier: [a-zA-Z][a-zA-Z0-9] *)
| [< ' ('A' .. 'Z' | 'a' .. 'z' as c); stream >] ->
let buffer = Buffer.create 1 in
Buffer.add_char buffer c;
lex_ident buffer stream
(* number: [0-9.]+ *)
| [< ' ('0' .. '9' as c); stream >] ->
let buffer = Buffer.create 1 in
Buffer.add_char buffer c;
lex_number buffer stream
(* Comment until end of line. *)
| [< ' ('#'); stream >] ->
lex_comment stream
(* Otherwise, just return the character as its ascii value. *)
| [< 'c; stream >] ->
[< 'Token.Kwd c; lex stream >]
(* end of stream. *)
| [< >] -> [< >]
and lex_number buffer = parser
| [< ' ('0' .. '9' | '.' as c); stream >] ->
Buffer.add_char buffer c;
lex_number buffer stream
| [< stream=lex >] ->
[< 'Token.Number (float_of_string (Buffer.contents buffer)); stream >]
and lex_ident buffer = parser
| [< ' ('A' .. 'Z' | 'a' .. 'z' | '0' .. '9' as c); stream >] ->
Buffer.add_char buffer c;
lex_ident buffer stream
| [< stream=lex >] ->
match Buffer.contents buffer with
| "def" -> [< 'Token.Def; stream >]
| "extern" -> [< 'Token.Extern; stream >]
| id -> [< 'Token.Ident id; stream >]
and lex_comment = parser
| [< ' ('\n'); stream=lex >] -> stream
| [< 'c; e=lex_comment >] -> e
| [< >] -> [< >]

View File

@ -0,0 +1,6 @@
open Ocamlbuild_plugin;;
ocaml_lib ~extern:true "llvm";;
ocaml_lib ~extern:true "llvm_analysis";;
flag ["link"; "ocaml"; "g++"] (S[A"-cc"; A"g++"]);;

View File

@ -0,0 +1,122 @@
(*===---------------------------------------------------------------------===
* Parser
*===---------------------------------------------------------------------===*)
(* binop_precedence - This holds the precedence for each binary operator that is
* defined *)
let binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10
(* precedence - Get the precedence of the pending binary operator token. *)
let precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1
(* primary
* ::= identifier
* ::= numberexpr
* ::= parenexpr *)
let rec parse_primary = parser
(* numberexpr ::= number *)
| [< 'Token.Number n >] -> Ast.Number n
(* parenexpr ::= '(' expression ')' *)
| [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e
(* identifierexpr
* ::= identifier
* ::= identifier '(' argumentexpr ')' *)
| [< 'Token.Ident id; stream >] ->
let rec parse_args accumulator = parser
| [< e=parse_expr; stream >] ->
begin parser
| [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e
| [< >] -> e :: accumulator
end stream
| [< >] -> accumulator
in
let rec parse_ident id = parser
(* Call. *)
| [< 'Token.Kwd '(';
args=parse_args [];
'Token.Kwd ')' ?? "expected ')'">] ->
Ast.Call (id, Array.of_list (List.rev args))
(* Simple variable ref. *)
| [< >] -> Ast.Variable id
in
parse_ident id stream
| [< >] -> raise (Stream.Error "unknown token when expecting an expression.")
(* binoprhs
* ::= ('+' primary)* *)
and parse_bin_rhs expr_prec lhs stream =
match Stream.peek stream with
(* If this is a binop, find its precedence. *)
| Some (Token.Kwd c) when Hashtbl.mem binop_precedence c ->
let token_prec = precedence c in
(* If this is a binop that binds at least as tightly as the current binop,
* consume it, otherwise we are done. *)
if token_prec < expr_prec then lhs else begin
(* Eat the binop. *)
Stream.junk stream;
(* Parse the primary expression after the binary operator. *)
let rhs = parse_primary stream in
(* Okay, we know this is a binop. *)
let rhs =
match Stream.peek stream with
| Some (Token.Kwd c2) ->
(* If BinOp binds less tightly with rhs than the operator after
* rhs, let the pending operator take rhs as its lhs. *)
let next_prec = precedence c2 in
if token_prec < next_prec
then parse_bin_rhs (token_prec + 1) rhs stream
else rhs
| _ -> rhs
in
(* Merge lhs/rhs. *)
let lhs = Ast.Binary (c, lhs, rhs) in
parse_bin_rhs expr_prec lhs stream
end
| _ -> lhs
(* expression
* ::= primary binoprhs *)
and parse_expr = parser
| [< lhs=parse_primary; stream >] -> parse_bin_rhs 0 lhs stream
(* prototype
* ::= id '(' id* ')' *)
let parse_prototype =
let rec parse_args accumulator = parser
| [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e
| [< >] -> accumulator
in
parser
| [< 'Token.Ident id;
'Token.Kwd '(' ?? "expected '(' in prototype";
args=parse_args [];
'Token.Kwd ')' ?? "expected ')' in prototype" >] ->
(* success. *)
Ast.Prototype (id, Array.of_list (List.rev args))
| [< >] ->
raise (Stream.Error "expected function name in prototype")
(* definition ::= 'def' prototype expression *)
let parse_definition = parser
| [< 'Token.Def; p=parse_prototype; e=parse_expr >] ->
Ast.Function (p, e)
(* toplevelexpr ::= expression *)
let parse_toplevel = parser
| [< e=parse_expr >] ->
(* Make an anonymous proto. *)
Ast.Function (Ast.Prototype ("", [||]), e)
(* external ::= 'extern' prototype *)
let parse_extern = parser
| [< 'Token.Extern; e=parse_prototype >] -> e

View File

@ -0,0 +1,15 @@
(*===----------------------------------------------------------------------===
* Lexer Tokens
*===----------------------------------------------------------------------===*)
(* The lexer returns these 'Kwd' if it is an unknown character, otherwise one of
* these others for known things. *)
type token =
(* commands *)
| Def | Extern
(* primary *)
| Ident of string | Number of float
(* unknown *)
| Kwd of char

View File

@ -0,0 +1,39 @@
(*===----------------------------------------------------------------------===
* Top-Level parsing and JIT Driver
*===----------------------------------------------------------------------===*)
open Llvm
(* top ::= definition | external | expression | ';' *)
let rec main_loop stream =
match Stream.peek stream with
| None -> ()
(* ignore top-level semicolons. *)
| Some (Token.Kwd ';') ->
Stream.junk stream;
main_loop stream
| Some token ->
begin
try match token with
| Token.Def ->
let e = Parser.parse_definition stream in
print_endline "parsed a function definition.";
dump_value (Codegen.codegen_func e);
| Token.Extern ->
let e = Parser.parse_extern stream in
print_endline "parsed an extern.";
dump_value (Codegen.codegen_proto e);
| _ ->
(* Evaluate a top-level expression into an anonymous function. *)
let e = Parser.parse_toplevel stream in
print_endline "parsed a top-level expr";
dump_value (Codegen.codegen_func e);
with Stream.Error s | Codegen.Error s ->
(* Skip token for error recovery. *)
Stream.junk stream;
print_endline s;
end;
print_string "ready> "; flush stdout;
main_loop stream

View File

@ -0,0 +1,26 @@
(*===----------------------------------------------------------------------===
* Main driver code.
*===----------------------------------------------------------------------===*)
open Llvm
let main () =
(* Install standard binary operators.
* 1 is the lowest precedence. *)
Hashtbl.add Parser.binop_precedence '<' 10;
Hashtbl.add Parser.binop_precedence '+' 20;
Hashtbl.add Parser.binop_precedence '-' 20;
Hashtbl.add Parser.binop_precedence '*' 40; (* highest. *)
(* Prime the first token. *)
print_string "ready> "; flush stdout;
let stream = Lexer.lex (Stream.of_channel stdin) in
(* Run the main "interpreter loop" now. *)
Toplevel.main_loop stream;
(* Print out all the generated code. *)
dump_module Codegen.the_module
;;
main ()

View File

@ -0,0 +1,25 @@
##===- examples/OCaml-Kaleidoscope/Chapter4/Makefile -------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
#
# This is the makefile for the Objective Caml kaleidoscope tutorial, chapter 4.
#
##===----------------------------------------------------------------------===##
LEVEL := ../../..
TOOLNAME := OCaml-Kaleidoscope-Ch4
EXAMPLE_TOOL := 1
UsedComponents := core
UsedOcamLibs := llvm llvm_analysis llvm_executionengine llvm_target \
llvm_scalar_opts
OCAMLCFLAGS += -pp camlp4of
ExcludeSources = $(PROJ_SRC_DIR)/myocamlbuild.ml
include $(LEVEL)/bindings/ocaml/Makefile.ocaml

View File

@ -0,0 +1,4 @@
<{lexer,parser}.ml>: use_camlp4, pp(camlp4of)
<*.{byte,native}>: g++, use_llvm, use_llvm_analysis
<*.{byte,native}>: use_llvm_executionengine, use_llvm_target
<*.{byte,native}>: use_llvm_scalar_opts, use_bindings

View File

@ -0,0 +1,25 @@
(*===----------------------------------------------------------------------===
* Abstract Syntax Tree (aka Parse Tree)
*===----------------------------------------------------------------------===*)
(* expr - Base type for all expression nodes. *)
type expr =
(* variant for numeric literals like "1.0". *)
| Number of float
(* variant for referencing a variable, like "a". *)
| Variable of string
(* variant for a binary operator. *)
| Binary of char * expr * expr
(* variant for function calls. *)
| Call of string * expr array
(* 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
(* func - This type represents a function definition itself. *)
type func = Function of proto * expr

View File

@ -0,0 +1,7 @@
#include <stdio.h>
/* putchard - putchar that takes a double and returns 0. */
extern double putchard(double X) {
putchar((char)X);
return 0;
}

View File

@ -0,0 +1,103 @@
(*===----------------------------------------------------------------------===
* Code Generation
*===----------------------------------------------------------------------===*)
open Llvm
exception Error of string
let context = global_context ()
let the_module = create_module context "my cool jit"
let builder = builder context
let named_values:(string, llvalue) Hashtbl.t = Hashtbl.create 10
let double_type = double_type context
let rec codegen_expr = function
| Ast.Number n -> const_float double_type n
| Ast.Variable name ->
(try Hashtbl.find named_values name with
| Not_found -> raise (Error "unknown variable name"))
| Ast.Binary (op, lhs, rhs) ->
let lhs_val = codegen_expr lhs in
let rhs_val = codegen_expr rhs in
begin
match op with
| '+' -> build_add lhs_val rhs_val "addtmp" builder
| '-' -> build_sub lhs_val rhs_val "subtmp" builder
| '*' -> build_mul lhs_val rhs_val "multmp" builder
| '<' ->
(* 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")
end
| Ast.Call (callee, args) ->
(* Look up the name in the module table. *)
let callee =
match lookup_function callee the_module with
| Some callee -> callee
| None -> raise (Error "unknown function referenced")
in
let params = params callee in
(* If argument mismatch error. *)
if Array.length params == Array.length args then () else
raise (Error "incorrect # arguments passed");
let args = Array.map codegen_expr args in
build_call callee args "calltmp" builder
let codegen_proto = function
| Ast.Prototype (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
let f =
match lookup_function name the_module with
| None -> declare_function name ft the_module
(* If 'f' conflicted, there was already something named 'name'. If it
* has a body, don't allow redefinition or reextern. *)
| Some f ->
(* If 'f' already has a body, reject this. *)
if block_begin f <> At_end f then
raise (Error "redefinition of function");
(* If 'f' took a different number of arguments, reject. *)
if element_type (type_of f) <> ft then
raise (Error "redefinition of function with different # args");
f
in
(* Set names for all arguments. *)
Array.iteri (fun i a ->
let n = args.(i) in
set_value_name n a;
Hashtbl.add named_values n a;
) (params f);
f
let codegen_func the_fpm = function
| Ast.Function (proto, body) ->
Hashtbl.clear named_values;
let the_function = codegen_proto proto in
(* Create a new basic block to start insertion into. *)
let bb = append_block context "entry" the_function in
position_at_end bb builder;
try
let ret_val = codegen_expr body in
(* Finish off the function. *)
let _ = build_ret ret_val builder in
(* Validate the generated code, checking for consistency. *)
Llvm_analysis.assert_valid_function the_function;
(* Optimize the function. *)
let _ = PassManager.run_function the_function the_fpm in
the_function
with e ->
delete_function the_function;
raise e

View File

@ -0,0 +1,52 @@
(*===----------------------------------------------------------------------===
* Lexer
*===----------------------------------------------------------------------===*)
let rec lex = parser
(* Skip any whitespace. *)
| [< ' (' ' | '\n' | '\r' | '\t'); stream >] -> lex stream
(* identifier: [a-zA-Z][a-zA-Z0-9] *)
| [< ' ('A' .. 'Z' | 'a' .. 'z' as c); stream >] ->
let buffer = Buffer.create 1 in
Buffer.add_char buffer c;
lex_ident buffer stream
(* number: [0-9.]+ *)
| [< ' ('0' .. '9' as c); stream >] ->
let buffer = Buffer.create 1 in
Buffer.add_char buffer c;
lex_number buffer stream
(* Comment until end of line. *)
| [< ' ('#'); stream >] ->
lex_comment stream
(* Otherwise, just return the character as its ascii value. *)
| [< 'c; stream >] ->
[< 'Token.Kwd c; lex stream >]
(* end of stream. *)
| [< >] -> [< >]
and lex_number buffer = parser
| [< ' ('0' .. '9' | '.' as c); stream >] ->
Buffer.add_char buffer c;
lex_number buffer stream
| [< stream=lex >] ->
[< 'Token.Number (float_of_string (Buffer.contents buffer)); stream >]
and lex_ident buffer = parser
| [< ' ('A' .. 'Z' | 'a' .. 'z' | '0' .. '9' as c); stream >] ->
Buffer.add_char buffer c;
lex_ident buffer stream
| [< stream=lex >] ->
match Buffer.contents buffer with
| "def" -> [< 'Token.Def; stream >]
| "extern" -> [< 'Token.Extern; stream >]
| id -> [< 'Token.Ident id; stream >]
and lex_comment = parser
| [< ' ('\n'); stream=lex >] -> stream
| [< 'c; e=lex_comment >] -> e
| [< >] -> [< >]

View File

@ -0,0 +1,10 @@
open Ocamlbuild_plugin;;
ocaml_lib ~extern:true "llvm";;
ocaml_lib ~extern:true "llvm_analysis";;
ocaml_lib ~extern:true "llvm_executionengine";;
ocaml_lib ~extern:true "llvm_target";;
ocaml_lib ~extern:true "llvm_scalar_opts";;
flag ["link"; "ocaml"; "g++"] (S[A"-cc"; A"g++"]);;
dep ["link"; "ocaml"; "use_bindings"] ["bindings.o"];;

View File

@ -0,0 +1,122 @@
(*===---------------------------------------------------------------------===
* Parser
*===---------------------------------------------------------------------===*)
(* binop_precedence - This holds the precedence for each binary operator that is
* defined *)
let binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10
(* precedence - Get the precedence of the pending binary operator token. *)
let precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1
(* primary
* ::= identifier
* ::= numberexpr
* ::= parenexpr *)
let rec parse_primary = parser
(* numberexpr ::= number *)
| [< 'Token.Number n >] -> Ast.Number n
(* parenexpr ::= '(' expression ')' *)
| [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e
(* identifierexpr
* ::= identifier
* ::= identifier '(' argumentexpr ')' *)
| [< 'Token.Ident id; stream >] ->
let rec parse_args accumulator = parser
| [< e=parse_expr; stream >] ->
begin parser
| [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e
| [< >] -> e :: accumulator
end stream
| [< >] -> accumulator
in
let rec parse_ident id = parser
(* Call. *)
| [< 'Token.Kwd '(';
args=parse_args [];
'Token.Kwd ')' ?? "expected ')'">] ->
Ast.Call (id, Array.of_list (List.rev args))
(* Simple variable ref. *)
| [< >] -> Ast.Variable id
in
parse_ident id stream
| [< >] -> raise (Stream.Error "unknown token when expecting an expression.")
(* binoprhs
* ::= ('+' primary)* *)
and parse_bin_rhs expr_prec lhs stream =
match Stream.peek stream with
(* If this is a binop, find its precedence. *)
| Some (Token.Kwd c) when Hashtbl.mem binop_precedence c ->
let token_prec = precedence c in
(* If this is a binop that binds at least as tightly as the current binop,
* consume it, otherwise we are done. *)
if token_prec < expr_prec then lhs else begin
(* Eat the binop. *)
Stream.junk stream;
(* Parse the primary expression after the binary operator. *)
let rhs = parse_primary stream in
(* Okay, we know this is a binop. *)
let rhs =
match Stream.peek stream with
| Some (Token.Kwd c2) ->
(* If BinOp binds less tightly with rhs than the operator after
* rhs, let the pending operator take rhs as its lhs. *)
let next_prec = precedence c2 in
if token_prec < next_prec
then parse_bin_rhs (token_prec + 1) rhs stream
else rhs
| _ -> rhs
in
(* Merge lhs/rhs. *)
let lhs = Ast.Binary (c, lhs, rhs) in
parse_bin_rhs expr_prec lhs stream
end
| _ -> lhs
(* expression
* ::= primary binoprhs *)
and parse_expr = parser
| [< lhs=parse_primary; stream >] -> parse_bin_rhs 0 lhs stream
(* prototype
* ::= id '(' id* ')' *)
let parse_prototype =
let rec parse_args accumulator = parser
| [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e
| [< >] -> accumulator
in
parser
| [< 'Token.Ident id;
'Token.Kwd '(' ?? "expected '(' in prototype";
args=parse_args [];
'Token.Kwd ')' ?? "expected ')' in prototype" >] ->
(* success. *)
Ast.Prototype (id, Array.of_list (List.rev args))
| [< >] ->
raise (Stream.Error "expected function name in prototype")
(* definition ::= 'def' prototype expression *)
let parse_definition = parser
| [< 'Token.Def; p=parse_prototype; e=parse_expr >] ->
Ast.Function (p, e)
(* toplevelexpr ::= expression *)
let parse_toplevel = parser
| [< e=parse_expr >] ->
(* Make an anonymous proto. *)
Ast.Function (Ast.Prototype ("", [||]), e)
(* external ::= 'extern' prototype *)
let parse_extern = parser
| [< 'Token.Extern; e=parse_prototype >] -> e

View File

@ -0,0 +1,15 @@
(*===----------------------------------------------------------------------===
* Lexer Tokens
*===----------------------------------------------------------------------===*)
(* The lexer returns these 'Kwd' if it is an unknown character, otherwise one of
* these others for known things. *)
type token =
(* commands *)
| Def | Extern
(* primary *)
| Ident of string | Number of float
(* unknown *)
| Kwd of char

View File

@ -0,0 +1,49 @@
(*===----------------------------------------------------------------------===
* Top-Level parsing and JIT Driver
*===----------------------------------------------------------------------===*)
open Llvm
open Llvm_executionengine
(* top ::= definition | external | expression | ';' *)
let rec main_loop the_fpm the_execution_engine stream =
match Stream.peek stream with
| None -> ()
(* ignore top-level semicolons. *)
| Some (Token.Kwd ';') ->
Stream.junk stream;
main_loop the_fpm the_execution_engine stream
| Some token ->
begin
try match token with
| Token.Def ->
let e = Parser.parse_definition stream in
print_endline "parsed a function definition.";
dump_value (Codegen.codegen_func the_fpm e);
| Token.Extern ->
let e = Parser.parse_extern stream in
print_endline "parsed an extern.";
dump_value (Codegen.codegen_proto e);
| _ ->
(* Evaluate a top-level expression into an anonymous function. *)
let e = Parser.parse_toplevel stream in
print_endline "parsed a top-level expr";
let the_function = Codegen.codegen_func the_fpm e in
dump_value the_function;
(* JIT the function, returning a function pointer. *)
let result = ExecutionEngine.run_function the_function [||]
the_execution_engine in
print_string "Evaluated to ";
print_float (GenericValue.as_float Codegen.double_type result);
print_newline ();
with Stream.Error s | Codegen.Error s ->
(* Skip token for error recovery. *)
Stream.junk stream;
print_endline s;
end;
print_string "ready> "; flush stdout;
main_loop the_fpm the_execution_engine stream

View File

@ -0,0 +1,53 @@
(*===----------------------------------------------------------------------===
* Main driver code.
*===----------------------------------------------------------------------===*)
open Llvm
open Llvm_executionengine
open Llvm_target
open Llvm_scalar_opts
let main () =
ignore (initialize_native_target ());
(* Install standard binary operators.
* 1 is the lowest precedence. *)
Hashtbl.add Parser.binop_precedence '<' 10;
Hashtbl.add Parser.binop_precedence '+' 20;
Hashtbl.add Parser.binop_precedence '-' 20;
Hashtbl.add Parser.binop_precedence '*' 40; (* highest. *)
(* Prime the first token. *)
print_string "ready> "; flush stdout;
let stream = Lexer.lex (Stream.of_channel stdin) in
(* Create the JIT. *)
let the_execution_engine = ExecutionEngine.create Codegen.the_module in
let the_fpm = PassManager.create_function Codegen.the_module in
(* Set up the optimizer pipeline. Start with registering info about how the
* target lays out data structures. *)
TargetData.add (ExecutionEngine.target_data the_execution_engine) the_fpm;
(* Do simple "peephole" optimizations and bit-twiddling optzn. *)
add_instruction_combination the_fpm;
(* reassociate expressions. *)
add_reassociation the_fpm;
(* Eliminate Common SubExpressions. *)
add_gvn the_fpm;
(* Simplify the control flow graph (deleting unreachable blocks, etc). *)
add_cfg_simplification the_fpm;
ignore (PassManager.initialize the_fpm);
(* Run the main "interpreter loop" now. *)
Toplevel.main_loop the_fpm the_execution_engine stream;
(* Print out all the generated code. *)
dump_module Codegen.the_module
;;
main ()

View File

@ -0,0 +1,25 @@
##===- examples/OCaml-Kaleidoscope/Chapter5/Makefile -------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
#
# This is the makefile for the Objective Caml kaleidoscope tutorial, chapter 5.
#
##===----------------------------------------------------------------------===##
LEVEL := ../../..
TOOLNAME := OCaml-Kaleidoscope-Ch5
EXAMPLE_TOOL := 1
UsedComponents := core
UsedOcamLibs := llvm llvm_analysis llvm_executionengine llvm_target \
llvm_scalar_opts
OCAMLCFLAGS += -pp camlp4of
ExcludeSources = $(PROJ_SRC_DIR)/myocamlbuild.ml
include $(LEVEL)/bindings/ocaml/Makefile.ocaml

View File

@ -0,0 +1,4 @@
<{lexer,parser}.ml>: use_camlp4, pp(camlp4of)
<*.{byte,native}>: g++, use_llvm, use_llvm_analysis
<*.{byte,native}>: use_llvm_executionengine, use_llvm_target
<*.{byte,native}>: use_llvm_scalar_opts, use_bindings

View File

@ -0,0 +1,31 @@
(*===----------------------------------------------------------------------===
* Abstract Syntax Tree (aka Parse Tree)
*===----------------------------------------------------------------------===*)
(* expr - Base type for all expression nodes. *)
type expr =
(* variant for numeric literals like "1.0". *)
| Number of float
(* variant for referencing a variable, like "a". *)
| Variable of string
(* variant for a binary operator. *)
| Binary of char * expr * expr
(* variant for function calls. *)
| Call of string * expr array
(* variant for if/then/else. *)
| If of expr * expr * expr
(* variant for for/in. *)
| For of string * expr * expr * expr option * 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
(* func - This type represents a function definition itself. *)
type func = Function of proto * expr

View File

@ -0,0 +1,7 @@
#include <stdio.h>
/* putchard - putchar that takes a double and returns 0. */
extern double putchard(double X) {
putchar((char)X);
return 0;
}

View File

@ -0,0 +1,225 @@
(*===----------------------------------------------------------------------===
* Code Generation
*===----------------------------------------------------------------------===*)
open Llvm
exception Error of string
let context = global_context ()
let the_module = create_module context "my cool jit"
let builder = builder context
let named_values:(string, llvalue) Hashtbl.t = Hashtbl.create 10
let double_type = double_type context
let rec codegen_expr = function
| Ast.Number n -> const_float double_type n
| Ast.Variable name ->
(try Hashtbl.find named_values name with
| Not_found -> raise (Error "unknown variable name"))
| Ast.Binary (op, lhs, rhs) ->
let lhs_val = codegen_expr lhs in
let rhs_val = codegen_expr rhs in
begin
match op with
| '+' -> build_add lhs_val rhs_val "addtmp" builder
| '-' -> build_sub lhs_val rhs_val "subtmp" builder
| '*' -> build_mul lhs_val rhs_val "multmp" builder
| '<' ->
(* 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")
end
| Ast.Call (callee, args) ->
(* Look up the name in the module table. *)
let callee =
match lookup_function callee the_module with
| Some callee -> callee
| None -> raise (Error "unknown function referenced")
in
let params = params callee in
(* If argument mismatch error. *)
if Array.length params == Array.length args then () else
raise (Error "incorrect # arguments passed");
let args = Array.map codegen_expr args in
build_call callee args "calltmp" builder
| Ast.If (cond, then_, else_) ->
let cond = codegen_expr cond in
(* Convert condition to a bool by comparing equal to 0.0 *)
let zero = const_float double_type 0.0 in
let cond_val = build_fcmp Fcmp.One cond zero "ifcond" builder in
(* Grab the first block so that we might later add the conditional branch
* to it at the end of the function. *)
let start_bb = insertion_block builder in
let the_function = block_parent start_bb in
let then_bb = append_block context "then" the_function in
(* Emit 'then' value. *)
position_at_end then_bb builder;
let then_val = codegen_expr then_ in
(* Codegen of 'then' can change the current block, update then_bb for the
* phi. We create a new name because one is used for the phi node, and the
* other is used for the conditional branch. *)
let new_then_bb = insertion_block builder in
(* Emit 'else' value. *)
let else_bb = append_block context "else" the_function in
position_at_end else_bb builder;
let else_val = codegen_expr else_ in
(* Codegen of 'else' can change the current block, update else_bb for the
* phi. *)
let new_else_bb = insertion_block builder in
(* Emit merge block. *)
let merge_bb = append_block context "ifcont" the_function in
position_at_end merge_bb builder;
let incoming = [(then_val, new_then_bb); (else_val, new_else_bb)] in
let phi = build_phi incoming "iftmp" builder in
(* Return to the start block to add the conditional branch. *)
position_at_end start_bb builder;
ignore (build_cond_br cond_val then_bb else_bb builder);
(* Set a unconditional branch at the end of the 'then' block and the
* 'else' block to the 'merge' block. *)
position_at_end new_then_bb builder; ignore (build_br merge_bb builder);
position_at_end new_else_bb builder; ignore (build_br merge_bb builder);
(* Finally, set the builder to the end of the merge block. *)
position_at_end merge_bb builder;
phi
| Ast.For (var_name, start, end_, step, body) ->
(* Emit the start code first, without 'variable' in scope. *)
let start_val = codegen_expr start in
(* Make the new basic block for the loop header, inserting after current
* block. *)
let preheader_bb = insertion_block builder in
let the_function = block_parent preheader_bb in
let loop_bb = append_block context "loop" the_function in
(* Insert an explicit fall through from the current block to the
* loop_bb. *)
ignore (build_br loop_bb builder);
(* Start insertion in loop_bb. *)
position_at_end loop_bb builder;
(* Start the PHI node with an entry for start. *)
let variable = build_phi [(start_val, preheader_bb)] var_name builder in
(* Within the loop, the variable is defined equal to the PHI node. If it
* shadows an existing variable, we have to restore it, so save it
* now. *)
let old_val =
try Some (Hashtbl.find named_values var_name) with Not_found -> None
in
Hashtbl.add named_values var_name variable;
(* Emit the body of the loop. This, like any other expr, can change the
* current BB. Note that we ignore the value computed by the body, but
* don't allow an error *)
ignore (codegen_expr body);
(* Emit the step value. *)
let step_val =
match step with
| Some step -> codegen_expr step
(* If not specified, use 1.0. *)
| None -> const_float double_type 1.0
in
let next_var = build_add variable step_val "nextvar" builder in
(* Compute the end condition. *)
let end_cond = codegen_expr end_ in
(* Convert condition to a bool by comparing equal to 0.0. *)
let zero = const_float double_type 0.0 in
let end_cond = build_fcmp Fcmp.One end_cond zero "loopcond" builder in
(* Create the "after loop" block and insert it. *)
let loop_end_bb = insertion_block builder in
let after_bb = append_block context "afterloop" the_function in
(* Insert the conditional branch into the end of loop_end_bb. *)
ignore (build_cond_br end_cond loop_bb after_bb builder);
(* Any new code will be inserted in after_bb. *)
position_at_end after_bb builder;
(* Add a new entry to the PHI node for the backedge. *)
add_incoming (next_var, loop_end_bb) variable;
(* Restore the unshadowed variable. *)
begin match old_val with
| Some old_val -> Hashtbl.add named_values var_name old_val
| None -> ()
end;
(* for expr always returns 0.0. *)
const_null double_type
let codegen_proto = function
| Ast.Prototype (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
let f =
match lookup_function name the_module with
| None -> declare_function name ft the_module
(* If 'f' conflicted, there was already something named 'name'. If it
* has a body, don't allow redefinition or reextern. *)
| Some f ->
(* If 'f' already has a body, reject this. *)
if block_begin f <> At_end f then
raise (Error "redefinition of function");
(* If 'f' took a different number of arguments, reject. *)
if element_type (type_of f) <> ft then
raise (Error "redefinition of function with different # args");
f
in
(* Set names for all arguments. *)
Array.iteri (fun i a ->
let n = args.(i) in
set_value_name n a;
Hashtbl.add named_values n a;
) (params f);
f
let codegen_func the_fpm = function
| Ast.Function (proto, body) ->
Hashtbl.clear named_values;
let the_function = codegen_proto proto in
(* Create a new basic block to start insertion into. *)
let bb = append_block context "entry" the_function in
position_at_end bb builder;
try
let ret_val = codegen_expr body in
(* Finish off the function. *)
let _ = build_ret ret_val builder in
(* Validate the generated code, checking for consistency. *)
Llvm_analysis.assert_valid_function the_function;
(* Optimize the function. *)
let _ = PassManager.run_function the_function the_fpm in
the_function
with e ->
delete_function the_function;
raise e

View File

@ -0,0 +1,57 @@
(*===----------------------------------------------------------------------===
* Lexer
*===----------------------------------------------------------------------===*)
let rec lex = parser
(* Skip any whitespace. *)
| [< ' (' ' | '\n' | '\r' | '\t'); stream >] -> lex stream
(* identifier: [a-zA-Z][a-zA-Z0-9] *)
| [< ' ('A' .. 'Z' | 'a' .. 'z' as c); stream >] ->
let buffer = Buffer.create 1 in
Buffer.add_char buffer c;
lex_ident buffer stream
(* number: [0-9.]+ *)
| [< ' ('0' .. '9' as c); stream >] ->
let buffer = Buffer.create 1 in
Buffer.add_char buffer c;
lex_number buffer stream
(* Comment until end of line. *)
| [< ' ('#'); stream >] ->
lex_comment stream
(* Otherwise, just return the character as its ascii value. *)
| [< 'c; stream >] ->
[< 'Token.Kwd c; lex stream >]
(* end of stream. *)
| [< >] -> [< >]
and lex_number buffer = parser
| [< ' ('0' .. '9' | '.' as c); stream >] ->
Buffer.add_char buffer c;
lex_number buffer stream
| [< stream=lex >] ->
[< 'Token.Number (float_of_string (Buffer.contents buffer)); stream >]
and lex_ident buffer = parser
| [< ' ('A' .. 'Z' | 'a' .. 'z' | '0' .. '9' as c); stream >] ->
Buffer.add_char buffer c;
lex_ident buffer stream
| [< stream=lex >] ->
match Buffer.contents buffer with
| "def" -> [< 'Token.Def; stream >]
| "extern" -> [< 'Token.Extern; stream >]
| "if" -> [< 'Token.If; stream >]
| "then" -> [< 'Token.Then; stream >]
| "else" -> [< 'Token.Else; stream >]
| "for" -> [< 'Token.For; stream >]
| "in" -> [< 'Token.In; stream >]
| id -> [< 'Token.Ident id; stream >]
and lex_comment = parser
| [< ' ('\n'); stream=lex >] -> stream
| [< 'c; e=lex_comment >] -> e
| [< >] -> [< >]

View File

@ -0,0 +1,10 @@
open Ocamlbuild_plugin;;
ocaml_lib ~extern:true "llvm";;
ocaml_lib ~extern:true "llvm_analysis";;
ocaml_lib ~extern:true "llvm_executionengine";;
ocaml_lib ~extern:true "llvm_target";;
ocaml_lib ~extern:true "llvm_scalar_opts";;
flag ["link"; "ocaml"; "g++"] (S[A"-cc"; A"g++"]);;
dep ["link"; "ocaml"; "use_bindings"] ["bindings.o"];;

View File

@ -0,0 +1,158 @@
(*===---------------------------------------------------------------------===
* Parser
*===---------------------------------------------------------------------===*)
(* binop_precedence - This holds the precedence for each binary operator that is
* defined *)
let binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10
(* precedence - Get the precedence of the pending binary operator token. *)
let precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1
(* primary
* ::= identifier
* ::= numberexpr
* ::= parenexpr
* ::= ifexpr
* ::= forexpr *)
let rec parse_primary = parser
(* numberexpr ::= number *)
| [< 'Token.Number n >] -> Ast.Number n
(* parenexpr ::= '(' expression ')' *)
| [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e
(* identifierexpr
* ::= identifier
* ::= identifier '(' argumentexpr ')' *)
| [< 'Token.Ident id; stream >] ->
let rec parse_args accumulator = parser
| [< e=parse_expr; stream >] ->
begin parser
| [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e
| [< >] -> e :: accumulator
end stream
| [< >] -> accumulator
in
let rec parse_ident id = parser
(* Call. *)
| [< 'Token.Kwd '(';
args=parse_args [];
'Token.Kwd ')' ?? "expected ')'">] ->
Ast.Call (id, Array.of_list (List.rev args))
(* Simple variable ref. *)
| [< >] -> Ast.Variable id
in
parse_ident id stream
(* ifexpr ::= 'if' expr 'then' expr 'else' expr *)
| [< 'Token.If; c=parse_expr;
'Token.Then ?? "expected 'then'"; t=parse_expr;
'Token.Else ?? "expected 'else'"; e=parse_expr >] ->
Ast.If (c, t, e)
(* forexpr
::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression *)
| [< 'Token.For;
'Token.Ident id ?? "expected identifier after for";
'Token.Kwd '=' ?? "expected '=' after for";
stream >] ->
begin parser
| [<
start=parse_expr;
'Token.Kwd ',' ?? "expected ',' after for";
end_=parse_expr;
stream >] ->
let step =
begin parser
| [< 'Token.Kwd ','; step=parse_expr >] -> Some step
| [< >] -> None
end stream
in
begin parser
| [< 'Token.In; body=parse_expr >] ->
Ast.For (id, start, end_, step, body)
| [< >] ->
raise (Stream.Error "expected 'in' after for")
end stream
| [< >] ->
raise (Stream.Error "expected '=' after for")
end stream
| [< >] -> raise (Stream.Error "unknown token when expecting an expression.")
(* binoprhs
* ::= ('+' primary)* *)
and parse_bin_rhs expr_prec lhs stream =
match Stream.peek stream with
(* If this is a binop, find its precedence. *)
| Some (Token.Kwd c) when Hashtbl.mem binop_precedence c ->
let token_prec = precedence c in
(* If this is a binop that binds at least as tightly as the current binop,
* consume it, otherwise we are done. *)
if token_prec < expr_prec then lhs else begin
(* Eat the binop. *)
Stream.junk stream;
(* Parse the primary expression after the binary operator. *)
let rhs = parse_primary stream in
(* Okay, we know this is a binop. *)
let rhs =
match Stream.peek stream with
| Some (Token.Kwd c2) ->
(* If BinOp binds less tightly with rhs than the operator after
* rhs, let the pending operator take rhs as its lhs. *)
let next_prec = precedence c2 in
if token_prec < next_prec
then parse_bin_rhs (token_prec + 1) rhs stream
else rhs
| _ -> rhs
in
(* Merge lhs/rhs. *)
let lhs = Ast.Binary (c, lhs, rhs) in
parse_bin_rhs expr_prec lhs stream
end
| _ -> lhs
(* expression
* ::= primary binoprhs *)
and parse_expr = parser
| [< lhs=parse_primary; stream >] -> parse_bin_rhs 0 lhs stream
(* prototype
* ::= id '(' id* ')' *)
let parse_prototype =
let rec parse_args accumulator = parser
| [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e
| [< >] -> accumulator
in
parser
| [< 'Token.Ident id;
'Token.Kwd '(' ?? "expected '(' in prototype";
args=parse_args [];
'Token.Kwd ')' ?? "expected ')' in prototype" >] ->
(* success. *)
Ast.Prototype (id, Array.of_list (List.rev args))
| [< >] ->
raise (Stream.Error "expected function name in prototype")
(* definition ::= 'def' prototype expression *)
let parse_definition = parser
| [< 'Token.Def; p=parse_prototype; e=parse_expr >] ->
Ast.Function (p, e)
(* toplevelexpr ::= expression *)
let parse_toplevel = parser
| [< e=parse_expr >] ->
(* Make an anonymous proto. *)
Ast.Function (Ast.Prototype ("", [||]), e)
(* external ::= 'extern' prototype *)
let parse_extern = parser
| [< 'Token.Extern; e=parse_prototype >] -> e

View File

@ -0,0 +1,19 @@
(*===----------------------------------------------------------------------===
* Lexer Tokens
*===----------------------------------------------------------------------===*)
(* The lexer returns these 'Kwd' if it is an unknown character, otherwise one of
* these others for known things. *)
type token =
(* commands *)
| Def | Extern
(* primary *)
| Ident of string | Number of float
(* unknown *)
| Kwd of char
(* control *)
| If | Then | Else
| For | In

View File

@ -0,0 +1,49 @@
(*===----------------------------------------------------------------------===
* Top-Level parsing and JIT Driver
*===----------------------------------------------------------------------===*)
open Llvm
open Llvm_executionengine
(* top ::= definition | external | expression | ';' *)
let rec main_loop the_fpm the_execution_engine stream =
match Stream.peek stream with
| None -> ()
(* ignore top-level semicolons. *)
| Some (Token.Kwd ';') ->
Stream.junk stream;
main_loop the_fpm the_execution_engine stream
| Some token ->
begin
try match token with
| Token.Def ->
let e = Parser.parse_definition stream in
print_endline "parsed a function definition.";
dump_value (Codegen.codegen_func the_fpm e);
| Token.Extern ->
let e = Parser.parse_extern stream in
print_endline "parsed an extern.";
dump_value (Codegen.codegen_proto e);
| _ ->
(* Evaluate a top-level expression into an anonymous function. *)
let e = Parser.parse_toplevel stream in
print_endline "parsed a top-level expr";
let the_function = Codegen.codegen_func the_fpm e in
dump_value the_function;
(* JIT the function, returning a function pointer. *)
let result = ExecutionEngine.run_function the_function [||]
the_execution_engine in
print_string "Evaluated to ";
print_float (GenericValue.as_float Codegen.double_type result);
print_newline ();
with Stream.Error s | Codegen.Error s ->
(* Skip token for error recovery. *)
Stream.junk stream;
print_endline s;
end;
print_string "ready> "; flush stdout;
main_loop the_fpm the_execution_engine stream

View File

@ -0,0 +1,53 @@
(*===----------------------------------------------------------------------===
* Main driver code.
*===----------------------------------------------------------------------===*)
open Llvm
open Llvm_executionengine
open Llvm_target
open Llvm_scalar_opts
let main () =
ignore (initialize_native_target ());
(* Install standard binary operators.
* 1 is the lowest precedence. *)
Hashtbl.add Parser.binop_precedence '<' 10;
Hashtbl.add Parser.binop_precedence '+' 20;
Hashtbl.add Parser.binop_precedence '-' 20;
Hashtbl.add Parser.binop_precedence '*' 40; (* highest. *)
(* Prime the first token. *)
print_string "ready> "; flush stdout;
let stream = Lexer.lex (Stream.of_channel stdin) in
(* Create the JIT. *)
let the_execution_engine = ExecutionEngine.create Codegen.the_module in
let the_fpm = PassManager.create_function Codegen.the_module in
(* Set up the optimizer pipeline. Start with registering info about how the
* target lays out data structures. *)
TargetData.add (ExecutionEngine.target_data the_execution_engine) the_fpm;
(* Do simple "peephole" optimizations and bit-twiddling optzn. *)
add_instruction_combination the_fpm;
(* reassociate expressions. *)
add_reassociation the_fpm;
(* Eliminate Common SubExpressions. *)
add_gvn the_fpm;
(* Simplify the control flow graph (deleting unreachable blocks, etc). *)
add_cfg_simplification the_fpm;
ignore (PassManager.initialize the_fpm);
(* Run the main "interpreter loop" now. *)
Toplevel.main_loop the_fpm the_execution_engine stream;
(* Print out all the generated code. *)
dump_module Codegen.the_module
;;
main ()

View File

@ -0,0 +1,25 @@
##===- examples/OCaml-Kaleidoscope/Chapter6/Makefile -------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
#
# This is the makefile for the Objective Caml kaleidoscope tutorial, chapter 6.
#
##===----------------------------------------------------------------------===##
LEVEL := ../../..
TOOLNAME := OCaml-Kaleidoscope-Ch6
EXAMPLE_TOOL := 1
UsedComponents := core
UsedOcamLibs := llvm llvm_analysis llvm_executionengine llvm_target \
llvm_scalar_opts
OCAMLCFLAGS += -pp camlp4of
ExcludeSources = $(PROJ_SRC_DIR)/myocamlbuild.ml
include $(LEVEL)/bindings/ocaml/Makefile.ocaml

View File

@ -0,0 +1,4 @@
<{lexer,parser}.ml>: use_camlp4, pp(camlp4of)
<*.{byte,native}>: g++, use_llvm, use_llvm_analysis
<*.{byte,native}>: use_llvm_executionengine, use_llvm_target
<*.{byte,native}>: use_llvm_scalar_opts, use_bindings

View File

@ -0,0 +1,36 @@
(*===----------------------------------------------------------------------===
* Abstract Syntax Tree (aka Parse Tree)
*===----------------------------------------------------------------------===*)
(* expr - Base type for all expression nodes. *)
type expr =
(* variant for numeric literals like "1.0". *)
| Number of float
(* variant for referencing a variable, like "a". *)
| Variable of string
(* variant for a unary operator. *)
| Unary of char * expr
(* variant for a binary operator. *)
| Binary of char * expr * expr
(* variant for function calls. *)
| Call of string * expr array
(* variant for if/then/else. *)
| If of expr * expr * expr
(* variant for for/in. *)
| For of string * expr * expr * expr option * 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
| BinOpPrototype of string * string array * int
(* func - This type represents a function definition itself. *)
type func = Function of proto * expr

View File

@ -0,0 +1,13 @@
#include <stdio.h>
/* putchard - putchar that takes a double and returns 0. */
extern double putchard(double X) {
putchar((char)X);
return 0;
}
/* printd - printf that takes a double prints it as "%f\n", returning 0. */
extern double printd(double X) {
printf("%f\n", X);
return 0;
}

View File

@ -0,0 +1,251 @@
(*===----------------------------------------------------------------------===
* Code Generation
*===----------------------------------------------------------------------===*)
open Llvm
exception Error of string
let context = global_context ()
let the_module = create_module context "my cool jit"
let builder = builder context
let named_values:(string, llvalue) Hashtbl.t = Hashtbl.create 10
let double_type = double_type context
let rec codegen_expr = function
| Ast.Number n -> const_float double_type n
| Ast.Variable name ->
(try Hashtbl.find named_values name with
| Not_found -> raise (Error "unknown variable name"))
| Ast.Unary (op, operand) ->
let operand = codegen_expr operand in
let callee = "unary" ^ (String.make 1 op) in
let callee =
match lookup_function callee the_module with
| Some callee -> callee
| None -> raise (Error "unknown unary operator")
in
build_call callee [|operand|] "unop" builder
| Ast.Binary (op, lhs, rhs) ->
let lhs_val = codegen_expr lhs in
let rhs_val = codegen_expr rhs in
begin
match op with
| '+' -> build_add lhs_val rhs_val "addtmp" builder
| '-' -> build_sub lhs_val rhs_val "subtmp" builder
| '*' -> build_mul lhs_val rhs_val "multmp" builder
| '<' ->
(* 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
| _ ->
(* 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. *)
let callee =
match lookup_function callee the_module with
| Some callee -> callee
| None -> raise (Error "unknown function referenced")
in
let params = params callee in
(* If argument mismatch error. *)
if Array.length params == Array.length args then () else
raise (Error "incorrect # arguments passed");
let args = Array.map codegen_expr args in
build_call callee args "calltmp" builder
| Ast.If (cond, then_, else_) ->
let cond = codegen_expr cond in
(* Convert condition to a bool by comparing equal to 0.0 *)
let zero = const_float double_type 0.0 in
let cond_val = build_fcmp Fcmp.One cond zero "ifcond" builder in
(* Grab the first block so that we might later add the conditional branch
* to it at the end of the function. *)
let start_bb = insertion_block builder in
let the_function = block_parent start_bb in
let then_bb = append_block context "then" the_function in
(* Emit 'then' value. *)
position_at_end then_bb builder;
let then_val = codegen_expr then_ in
(* Codegen of 'then' can change the current block, update then_bb for the
* phi. We create a new name because one is used for the phi node, and the
* other is used for the conditional branch. *)
let new_then_bb = insertion_block builder in
(* Emit 'else' value. *)
let else_bb = append_block context "else" the_function in
position_at_end else_bb builder;
let else_val = codegen_expr else_ in
(* Codegen of 'else' can change the current block, update else_bb for the
* phi. *)
let new_else_bb = insertion_block builder in
(* Emit merge block. *)
let merge_bb = append_block context "ifcont" the_function in
position_at_end merge_bb builder;
let incoming = [(then_val, new_then_bb); (else_val, new_else_bb)] in
let phi = build_phi incoming "iftmp" builder in
(* Return to the start block to add the conditional branch. *)
position_at_end start_bb builder;
ignore (build_cond_br cond_val then_bb else_bb builder);
(* Set a unconditional branch at the end of the 'then' block and the
* 'else' block to the 'merge' block. *)
position_at_end new_then_bb builder; ignore (build_br merge_bb builder);
position_at_end new_else_bb builder; ignore (build_br merge_bb builder);
(* Finally, set the builder to the end of the merge block. *)
position_at_end merge_bb builder;
phi
| Ast.For (var_name, start, end_, step, body) ->
(* Emit the start code first, without 'variable' in scope. *)
let start_val = codegen_expr start in
(* Make the new basic block for the loop header, inserting after current
* block. *)
let preheader_bb = insertion_block builder in
let the_function = block_parent preheader_bb in
let loop_bb = append_block context "loop" the_function in
(* Insert an explicit fall through from the current block to the
* loop_bb. *)
ignore (build_br loop_bb builder);
(* Start insertion in loop_bb. *)
position_at_end loop_bb builder;
(* Start the PHI node with an entry for start. *)
let variable = build_phi [(start_val, preheader_bb)] var_name builder in
(* Within the loop, the variable is defined equal to the PHI node. If it
* shadows an existing variable, we have to restore it, so save it
* now. *)
let old_val =
try Some (Hashtbl.find named_values var_name) with Not_found -> None
in
Hashtbl.add named_values var_name variable;
(* Emit the body of the loop. This, like any other expr, can change the
* current BB. Note that we ignore the value computed by the body, but
* don't allow an error *)
ignore (codegen_expr body);
(* Emit the step value. *)
let step_val =
match step with
| Some step -> codegen_expr step
(* If not specified, use 1.0. *)
| None -> const_float double_type 1.0
in
let next_var = build_add variable step_val "nextvar" builder in
(* Compute the end condition. *)
let end_cond = codegen_expr end_ in
(* Convert condition to a bool by comparing equal to 0.0. *)
let zero = const_float double_type 0.0 in
let end_cond = build_fcmp Fcmp.One end_cond zero "loopcond" builder in
(* Create the "after loop" block and insert it. *)
let loop_end_bb = insertion_block builder in
let after_bb = append_block context "afterloop" the_function in
(* Insert the conditional branch into the end of loop_end_bb. *)
ignore (build_cond_br end_cond loop_bb after_bb builder);
(* Any new code will be inserted in after_bb. *)
position_at_end after_bb builder;
(* Add a new entry to the PHI node for the backedge. *)
add_incoming (next_var, loop_end_bb) variable;
(* Restore the unshadowed variable. *)
begin match old_val with
| Some old_val -> Hashtbl.add named_values var_name old_val
| None -> ()
end;
(* for expr always returns 0.0. *)
const_null double_type
let codegen_proto = function
| 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
let f =
match lookup_function name the_module with
| None -> declare_function name ft the_module
(* If 'f' conflicted, there was already something named 'name'. If it
* has a body, don't allow redefinition or reextern. *)
| Some f ->
(* If 'f' already has a body, reject this. *)
if block_begin f <> At_end f then
raise (Error "redefinition of function");
(* If 'f' took a different number of arguments, reject. *)
if element_type (type_of f) <> ft then
raise (Error "redefinition of function with different # args");
f
in
(* Set names for all arguments. *)
Array.iteri (fun i a ->
let n = args.(i) in
set_value_name n a;
Hashtbl.add named_values n a;
) (params f);
f
let codegen_func the_fpm = function
| Ast.Function (proto, body) ->
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;
try
let ret_val = codegen_expr body in
(* Finish off the function. *)
let _ = build_ret ret_val builder in
(* Validate the generated code, checking for consistency. *)
Llvm_analysis.assert_valid_function the_function;
(* Optimize the function. *)
let _ = PassManager.run_function the_function the_fpm in
the_function
with e ->
delete_function the_function;
raise e

View File

@ -0,0 +1,59 @@
(*===----------------------------------------------------------------------===
* Lexer
*===----------------------------------------------------------------------===*)
let rec lex = parser
(* Skip any whitespace. *)
| [< ' (' ' | '\n' | '\r' | '\t'); stream >] -> lex stream
(* identifier: [a-zA-Z][a-zA-Z0-9] *)
| [< ' ('A' .. 'Z' | 'a' .. 'z' as c); stream >] ->
let buffer = Buffer.create 1 in
Buffer.add_char buffer c;
lex_ident buffer stream
(* number: [0-9.]+ *)
| [< ' ('0' .. '9' as c); stream >] ->
let buffer = Buffer.create 1 in
Buffer.add_char buffer c;
lex_number buffer stream
(* Comment until end of line. *)
| [< ' ('#'); stream >] ->
lex_comment stream
(* Otherwise, just return the character as its ascii value. *)
| [< 'c; stream >] ->
[< 'Token.Kwd c; lex stream >]
(* end of stream. *)
| [< >] -> [< >]
and lex_number buffer = parser
| [< ' ('0' .. '9' | '.' as c); stream >] ->
Buffer.add_char buffer c;
lex_number buffer stream
| [< stream=lex >] ->
[< 'Token.Number (float_of_string (Buffer.contents buffer)); stream >]
and lex_ident buffer = parser
| [< ' ('A' .. 'Z' | 'a' .. 'z' | '0' .. '9' as c); stream >] ->
Buffer.add_char buffer c;
lex_ident buffer stream
| [< stream=lex >] ->
match Buffer.contents buffer with
| "def" -> [< 'Token.Def; stream >]
| "extern" -> [< 'Token.Extern; stream >]
| "if" -> [< 'Token.If; stream >]
| "then" -> [< 'Token.Then; stream >]
| "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
| [< ' ('\n'); stream=lex >] -> stream
| [< 'c; e=lex_comment >] -> e
| [< >] -> [< >]

View File

@ -0,0 +1,10 @@
open Ocamlbuild_plugin;;
ocaml_lib ~extern:true "llvm";;
ocaml_lib ~extern:true "llvm_analysis";;
ocaml_lib ~extern:true "llvm_executionengine";;
ocaml_lib ~extern:true "llvm_target";;
ocaml_lib ~extern:true "llvm_scalar_opts";;
flag ["link"; "ocaml"; "g++"] (S[A"-cc"; A"g++"]);;
dep ["link"; "ocaml"; "use_bindings"] ["bindings.o"];;

View File

@ -0,0 +1,195 @@
(*===---------------------------------------------------------------------===
* Parser
*===---------------------------------------------------------------------===*)
(* binop_precedence - This holds the precedence for each binary operator that is
* defined *)
let binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10
(* precedence - Get the precedence of the pending binary operator token. *)
let precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1
(* primary
* ::= identifier
* ::= numberexpr
* ::= parenexpr
* ::= ifexpr
* ::= forexpr *)
let rec parse_primary = parser
(* numberexpr ::= number *)
| [< 'Token.Number n >] -> Ast.Number n
(* parenexpr ::= '(' expression ')' *)
| [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e
(* identifierexpr
* ::= identifier
* ::= identifier '(' argumentexpr ')' *)
| [< 'Token.Ident id; stream >] ->
let rec parse_args accumulator = parser
| [< e=parse_expr; stream >] ->
begin parser
| [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e
| [< >] -> e :: accumulator
end stream
| [< >] -> accumulator
in
let rec parse_ident id = parser
(* Call. *)
| [< 'Token.Kwd '(';
args=parse_args [];
'Token.Kwd ')' ?? "expected ')'">] ->
Ast.Call (id, Array.of_list (List.rev args))
(* Simple variable ref. *)
| [< >] -> Ast.Variable id
in
parse_ident id stream
(* ifexpr ::= 'if' expr 'then' expr 'else' expr *)
| [< 'Token.If; c=parse_expr;
'Token.Then ?? "expected 'then'"; t=parse_expr;
'Token.Else ?? "expected 'else'"; e=parse_expr >] ->
Ast.If (c, t, e)
(* forexpr
::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression *)
| [< 'Token.For;
'Token.Ident id ?? "expected identifier after for";
'Token.Kwd '=' ?? "expected '=' after for";
stream >] ->
begin parser
| [<
start=parse_expr;
'Token.Kwd ',' ?? "expected ',' after for";
end_=parse_expr;
stream >] ->
let step =
begin parser
| [< 'Token.Kwd ','; step=parse_expr >] -> Some step
| [< >] -> None
end stream
in
begin parser
| [< 'Token.In; body=parse_expr >] ->
Ast.For (id, start, end_, step, body)
| [< >] ->
raise (Stream.Error "expected 'in' after for")
end stream
| [< >] ->
raise (Stream.Error "expected '=' after for")
end stream
| [< >] -> raise (Stream.Error "unknown token when expecting an expression.")
(* unary
* ::= primary
* ::= '!' unary *)
and parse_unary = parser
(* If this is a unary operator, read it. *)
| [< 'Token.Kwd op when op != '(' && op != ')'; operand=parse_expr >] ->
Ast.Unary (op, operand)
(* If the current token is not an operator, it must be a primary expr. *)
| [< stream >] -> parse_primary stream
(* binoprhs
* ::= ('+' primary)* *)
and parse_bin_rhs expr_prec lhs stream =
match Stream.peek stream with
(* If this is a binop, find its precedence. *)
| Some (Token.Kwd c) when Hashtbl.mem binop_precedence c ->
let token_prec = precedence c in
(* If this is a binop that binds at least as tightly as the current binop,
* consume it, otherwise we are done. *)
if token_prec < expr_prec then lhs else begin
(* Eat the binop. *)
Stream.junk stream;
(* Parse the unary expression after the binary operator. *)
let rhs = parse_unary stream in
(* Okay, we know this is a binop. *)
let rhs =
match Stream.peek stream with
| Some (Token.Kwd c2) ->
(* If BinOp binds less tightly with rhs than the operator after
* rhs, let the pending operator take rhs as its lhs. *)
let next_prec = precedence c2 in
if token_prec < next_prec
then parse_bin_rhs (token_prec + 1) rhs stream
else rhs
| _ -> rhs
in
(* Merge lhs/rhs. *)
let lhs = Ast.Binary (c, lhs, rhs) in
parse_bin_rhs expr_prec lhs stream
end
| _ -> lhs
(* expression
* ::= primary binoprhs *)
and parse_expr = parser
| [< lhs=parse_unary; stream >] -> parse_bin_rhs 0 lhs stream
(* prototype
* ::= 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";
args=parse_args [];
'Token.Kwd ')' ?? "expected ')' in 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")
(* definition ::= 'def' prototype expression *)
let parse_definition = parser
| [< 'Token.Def; p=parse_prototype; e=parse_expr >] ->
Ast.Function (p, e)
(* toplevelexpr ::= expression *)
let parse_toplevel = parser
| [< e=parse_expr >] ->
(* Make an anonymous proto. *)
Ast.Function (Ast.Prototype ("", [||]), e)
(* external ::= 'extern' prototype *)
let parse_extern = parser
| [< 'Token.Extern; e=parse_prototype >] -> e

View File

@ -0,0 +1,22 @@
(*===----------------------------------------------------------------------===
* Lexer Tokens
*===----------------------------------------------------------------------===*)
(* The lexer returns these 'Kwd' if it is an unknown character, otherwise one of
* these others for known things. *)
type token =
(* commands *)
| Def | Extern
(* primary *)
| Ident of string | Number of float
(* unknown *)
| Kwd of char
(* control *)
| If | Then | Else
| For | In
(* operators *)
| Binary | Unary

View File

@ -0,0 +1,49 @@
(*===----------------------------------------------------------------------===
* Top-Level parsing and JIT Driver
*===----------------------------------------------------------------------===*)
open Llvm
open Llvm_executionengine
(* top ::= definition | external | expression | ';' *)
let rec main_loop the_fpm the_execution_engine stream =
match Stream.peek stream with
| None -> ()
(* ignore top-level semicolons. *)
| Some (Token.Kwd ';') ->
Stream.junk stream;
main_loop the_fpm the_execution_engine stream
| Some token ->
begin
try match token with
| Token.Def ->
let e = Parser.parse_definition stream in
print_endline "parsed a function definition.";
dump_value (Codegen.codegen_func the_fpm e);
| Token.Extern ->
let e = Parser.parse_extern stream in
print_endline "parsed an extern.";
dump_value (Codegen.codegen_proto e);
| _ ->
(* Evaluate a top-level expression into an anonymous function. *)
let e = Parser.parse_toplevel stream in
print_endline "parsed a top-level expr";
let the_function = Codegen.codegen_func the_fpm e in
dump_value the_function;
(* JIT the function, returning a function pointer. *)
let result = ExecutionEngine.run_function the_function [||]
the_execution_engine in
print_string "Evaluated to ";
print_float (GenericValue.as_float Codegen.double_type result);
print_newline ();
with Stream.Error s | Codegen.Error s ->
(* Skip token for error recovery. *)
Stream.junk stream;
print_endline s;
end;
print_string "ready> "; flush stdout;
main_loop the_fpm the_execution_engine stream

View File

@ -0,0 +1,53 @@
(*===----------------------------------------------------------------------===
* Main driver code.
*===----------------------------------------------------------------------===*)
open Llvm
open Llvm_executionengine
open Llvm_target
open Llvm_scalar_opts
let main () =
ignore (initialize_native_target ());
(* Install standard binary operators.
* 1 is the lowest precedence. *)
Hashtbl.add Parser.binop_precedence '<' 10;
Hashtbl.add Parser.binop_precedence '+' 20;
Hashtbl.add Parser.binop_precedence '-' 20;
Hashtbl.add Parser.binop_precedence '*' 40; (* highest. *)
(* Prime the first token. *)
print_string "ready> "; flush stdout;
let stream = Lexer.lex (Stream.of_channel stdin) in
(* Create the JIT. *)
let the_execution_engine = ExecutionEngine.create Codegen.the_module in
let the_fpm = PassManager.create_function Codegen.the_module in
(* Set up the optimizer pipeline. Start with registering info about how the
* target lays out data structures. *)
TargetData.add (ExecutionEngine.target_data the_execution_engine) the_fpm;
(* Do simple "peephole" optimizations and bit-twiddling optzn. *)
add_instruction_combination the_fpm;
(* reassociate expressions. *)
add_reassociation the_fpm;
(* Eliminate Common SubExpressions. *)
add_gvn the_fpm;
(* Simplify the control flow graph (deleting unreachable blocks, etc). *)
add_cfg_simplification the_fpm;
ignore (PassManager.initialize the_fpm);
(* Run the main "interpreter loop" now. *)
Toplevel.main_loop the_fpm the_execution_engine stream;
(* Print out all the generated code. *)
dump_module Codegen.the_module
;;
main ()

View File

@ -0,0 +1,25 @@
##===- examples/OCaml-Kaleidoscope/Chapter7/Makefile -------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
#
# This is the makefile for the Objective Caml kaleidoscope tutorial, chapter 7.
#
##===----------------------------------------------------------------------===##
LEVEL := ../../..
TOOLNAME := OCaml-Kaleidoscope-Ch7
EXAMPLE_TOOL := 1
UsedComponents := core
UsedOcamLibs := llvm llvm_analysis llvm_executionengine llvm_target \
llvm_scalar_opts
OCAMLCFLAGS += -pp camlp4of
ExcludeSources = $(PROJ_SRC_DIR)/myocamlbuild.ml
include $(LEVEL)/bindings/ocaml/Makefile.ocaml

View File

@ -0,0 +1,4 @@
<{lexer,parser}.ml>: use_camlp4, pp(camlp4of)
<*.{byte,native}>: g++, use_llvm, use_llvm_analysis
<*.{byte,native}>: use_llvm_executionengine, use_llvm_target
<*.{byte,native}>: use_llvm_scalar_opts, use_bindings

View File

@ -0,0 +1,39 @@
(*===----------------------------------------------------------------------===
* Abstract Syntax Tree (aka Parse Tree)
*===----------------------------------------------------------------------===*)
(* expr - Base type for all expression nodes. *)
type expr =
(* variant for numeric literals like "1.0". *)
| Number of float
(* variant for referencing a variable, like "a". *)
| Variable of string
(* variant for a unary operator. *)
| Unary of char * expr
(* variant for a binary operator. *)
| Binary of char * expr * expr
(* variant for function calls. *)
| Call of string * expr array
(* variant for if/then/else. *)
| If of expr * expr * expr
(* variant for for/in. *)
| For of string * expr * expr * expr option * expr
(* variant for var/in. *)
| Var of (string * expr option) array * 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
| BinOpPrototype of string * string array * int
(* func - This type represents a function definition itself. *)
type func = Function of proto * expr

View File

@ -0,0 +1,13 @@
#include <stdio.h>
/* putchard - putchar that takes a double and returns 0. */
extern double putchard(double X) {
putchar((char)X);
return 0;
}
/* printd - printf that takes a double prints it as "%f\n", returning 0. */
extern double printd(double X) {
printf("%f\n", X);
return 0;
}

View File

@ -0,0 +1,370 @@
(*===----------------------------------------------------------------------===
* Code Generation
*===----------------------------------------------------------------------===*)
open Llvm
exception Error of string
let context = global_context ()
let the_module = create_module context "my cool jit"
let builder = builder context
let named_values:(string, llvalue) Hashtbl.t = Hashtbl.create 10
let double_type = double_type context
(* Create an alloca instruction in the entry block of the function. This
* is used for mutable variables etc. *)
let create_entry_block_alloca the_function var_name =
let builder = builder_at context (instr_begin (entry_block the_function)) in
build_alloca double_type var_name builder
let rec codegen_expr = function
| Ast.Number n -> const_float double_type n
| Ast.Variable name ->
let v = try Hashtbl.find named_values name with
| Not_found -> raise (Error "unknown variable name")
in
(* Load the value. *)
build_load v name builder
| Ast.Unary (op, operand) ->
let operand = codegen_expr operand in
let callee = "unary" ^ (String.make 1 op) in
let callee =
match lookup_function callee the_module with
| Some callee -> callee
| None -> raise (Error "unknown unary operator")
in
build_call callee [|operand|] "unop" builder
| Ast.Binary (op, lhs, rhs) ->
begin match op with
| '=' ->
(* Special case '=' because we don't want to emit the LHS as an
* expression. *)
let name =
match lhs with
| Ast.Variable name -> name
| _ -> raise (Error "destination of '=' must be a variable")
in
(* Codegen the rhs. *)
let val_ = codegen_expr rhs in
(* Lookup the name. *)
let variable = try Hashtbl.find named_values name with
| Not_found -> raise (Error "unknown variable name")
in
ignore(build_store val_ variable builder);
val_
| _ ->
let lhs_val = codegen_expr lhs in
let rhs_val = codegen_expr rhs in
begin
match op with
| '+' -> build_add lhs_val rhs_val "addtmp" builder
| '-' -> build_sub lhs_val rhs_val "subtmp" builder
| '*' -> build_mul lhs_val rhs_val "multmp" builder
| '<' ->
(* 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
| _ ->
(* 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
end
| Ast.Call (callee, args) ->
(* Look up the name in the module table. *)
let callee =
match lookup_function callee the_module with
| Some callee -> callee
| None -> raise (Error "unknown function referenced")
in
let params = params callee in
(* If argument mismatch error. *)
if Array.length params == Array.length args then () else
raise (Error "incorrect # arguments passed");
let args = Array.map codegen_expr args in
build_call callee args "calltmp" builder
| Ast.If (cond, then_, else_) ->
let cond = codegen_expr cond in
(* Convert condition to a bool by comparing equal to 0.0 *)
let zero = const_float double_type 0.0 in
let cond_val = build_fcmp Fcmp.One cond zero "ifcond" builder in
(* Grab the first block so that we might later add the conditional branch
* to it at the end of the function. *)
let start_bb = insertion_block builder in
let the_function = block_parent start_bb in
let then_bb = append_block context "then" the_function in
(* Emit 'then' value. *)
position_at_end then_bb builder;
let then_val = codegen_expr then_ in
(* Codegen of 'then' can change the current block, update then_bb for the
* phi. We create a new name because one is used for the phi node, and the
* other is used for the conditional branch. *)
let new_then_bb = insertion_block builder in
(* Emit 'else' value. *)
let else_bb = append_block context "else" the_function in
position_at_end else_bb builder;
let else_val = codegen_expr else_ in
(* Codegen of 'else' can change the current block, update else_bb for the
* phi. *)
let new_else_bb = insertion_block builder in
(* Emit merge block. *)
let merge_bb = append_block context "ifcont" the_function in
position_at_end merge_bb builder;
let incoming = [(then_val, new_then_bb); (else_val, new_else_bb)] in
let phi = build_phi incoming "iftmp" builder in
(* Return to the start block to add the conditional branch. *)
position_at_end start_bb builder;
ignore (build_cond_br cond_val then_bb else_bb builder);
(* Set a unconditional branch at the end of the 'then' block and the
* 'else' block to the 'merge' block. *)
position_at_end new_then_bb builder; ignore (build_br merge_bb builder);
position_at_end new_else_bb builder; ignore (build_br merge_bb builder);
(* Finally, set the builder to the end of the merge block. *)
position_at_end merge_bb builder;
phi
| Ast.For (var_name, start, end_, step, body) ->
(* Output this as:
* var = alloca double
* ...
* start = startexpr
* store start -> var
* goto loop
* loop:
* ...
* bodyexpr
* ...
* loopend:
* step = stepexpr
* endcond = endexpr
*
* curvar = load var
* nextvar = curvar + step
* store nextvar -> var
* br endcond, loop, endloop
* outloop: *)
let the_function = block_parent (insertion_block builder) in
(* Create an alloca for the variable in the entry block. *)
let alloca = create_entry_block_alloca the_function var_name in
(* Emit the start code first, without 'variable' in scope. *)
let start_val = codegen_expr start in
(* Store the value into the alloca. *)
ignore(build_store start_val alloca builder);
(* Make the new basic block for the loop header, inserting after current
* block. *)
let loop_bb = append_block context "loop" the_function in
(* Insert an explicit fall through from the current block to the
* loop_bb. *)
ignore (build_br loop_bb builder);
(* Start insertion in loop_bb. *)
position_at_end loop_bb builder;
(* Within the loop, the variable is defined equal to the PHI node. If it
* shadows an existing variable, we have to restore it, so save it
* now. *)
let old_val =
try Some (Hashtbl.find named_values var_name) with Not_found -> None
in
Hashtbl.add named_values var_name alloca;
(* Emit the body of the loop. This, like any other expr, can change the
* current BB. Note that we ignore the value computed by the body, but
* don't allow an error *)
ignore (codegen_expr body);
(* Emit the step value. *)
let step_val =
match step with
| Some step -> codegen_expr step
(* If not specified, use 1.0. *)
| None -> const_float double_type 1.0
in
(* Compute the end condition. *)
let end_cond = codegen_expr end_ in
(* Reload, increment, and restore the alloca. This handles the case where
* the body of the loop mutates the variable. *)
let cur_var = build_load alloca var_name builder in
let next_var = build_add cur_var step_val "nextvar" builder in
ignore(build_store next_var alloca builder);
(* Convert condition to a bool by comparing equal to 0.0. *)
let zero = const_float double_type 0.0 in
let end_cond = build_fcmp Fcmp.One end_cond zero "loopcond" builder in
(* Create the "after loop" block and insert it. *)
let after_bb = append_block context "afterloop" the_function in
(* Insert the conditional branch into the end of loop_end_bb. *)
ignore (build_cond_br end_cond loop_bb after_bb builder);
(* Any new code will be inserted in after_bb. *)
position_at_end after_bb builder;
(* Restore the unshadowed variable. *)
begin match old_val with
| Some old_val -> Hashtbl.add named_values var_name old_val
| None -> ()
end;
(* for expr always returns 0.0. *)
const_null double_type
| Ast.Var (var_names, body) ->
let old_bindings = ref [] in
let the_function = block_parent (insertion_block builder) in
(* Register all variables and emit their initializer. *)
Array.iter (fun (var_name, init) ->
(* Emit the initializer before adding the variable to scope, this
* prevents the initializer from referencing the variable itself, and
* permits stuff like this:
* var a = 1 in
* var a = a in ... # refers to outer 'a'. *)
let init_val =
match init with
| Some init -> codegen_expr init
(* If not specified, use 0.0. *)
| None -> const_float double_type 0.0
in
let alloca = create_entry_block_alloca the_function var_name in
ignore(build_store init_val alloca builder);
(* Remember the old variable binding so that we can restore the binding
* when we unrecurse. *)
begin
try
let old_value = Hashtbl.find named_values var_name in
old_bindings := (var_name, old_value) :: !old_bindings;
with Not_found -> ()
end;
(* Remember this binding. *)
Hashtbl.add named_values var_name alloca;
) var_names;
(* Codegen the body, now that all vars are in scope. *)
let body_val = codegen_expr body in
(* Pop all our variables from scope. *)
List.iter (fun (var_name, old_value) ->
Hashtbl.add named_values var_name old_value
) !old_bindings;
(* Return the body computation. *)
body_val
let codegen_proto = function
| 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
let f =
match lookup_function name the_module with
| None -> declare_function name ft the_module
(* If 'f' conflicted, there was already something named 'name'. If it
* has a body, don't allow redefinition or reextern. *)
| Some f ->
(* If 'f' already has a body, reject this. *)
if block_begin f <> At_end f then
raise (Error "redefinition of function");
(* If 'f' took a different number of arguments, reject. *)
if element_type (type_of f) <> ft then
raise (Error "redefinition of function with different # args");
f
in
(* Set names for all arguments. *)
Array.iteri (fun i a ->
let n = args.(i) in
set_value_name n a;
Hashtbl.add named_values n a;
) (params f);
f
(* Create an alloca for each argument and register the argument in the symbol
* table so that references to it will succeed. *)
let create_argument_allocas the_function proto =
let args = match proto with
| Ast.Prototype (_, args) | Ast.BinOpPrototype (_, args, _) -> args
in
Array.iteri (fun i ai ->
let var_name = args.(i) in
(* Create an alloca for this variable. *)
let alloca = create_entry_block_alloca the_function var_name in
(* Store the initial value into the alloca. *)
ignore(build_store ai alloca builder);
(* Add arguments to variable symbol table. *)
Hashtbl.add named_values var_name alloca;
) (params the_function)
let codegen_func the_fpm = function
| Ast.Function (proto, body) ->
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;
try
(* Add all arguments to the symbol table and create their allocas. *)
create_argument_allocas the_function proto;
let ret_val = codegen_expr body in
(* Finish off the function. *)
let _ = build_ret ret_val builder in
(* Validate the generated code, checking for consistency. *)
Llvm_analysis.assert_valid_function the_function;
(* Optimize the function. *)
let _ = PassManager.run_function the_function the_fpm in
the_function
with e ->
delete_function the_function;
raise e

View File

@ -0,0 +1,60 @@
(*===----------------------------------------------------------------------===
* Lexer
*===----------------------------------------------------------------------===*)
let rec lex = parser
(* Skip any whitespace. *)
| [< ' (' ' | '\n' | '\r' | '\t'); stream >] -> lex stream
(* identifier: [a-zA-Z][a-zA-Z0-9] *)
| [< ' ('A' .. 'Z' | 'a' .. 'z' as c); stream >] ->
let buffer = Buffer.create 1 in
Buffer.add_char buffer c;
lex_ident buffer stream
(* number: [0-9.]+ *)
| [< ' ('0' .. '9' as c); stream >] ->
let buffer = Buffer.create 1 in
Buffer.add_char buffer c;
lex_number buffer stream
(* Comment until end of line. *)
| [< ' ('#'); stream >] ->
lex_comment stream
(* Otherwise, just return the character as its ascii value. *)
| [< 'c; stream >] ->
[< 'Token.Kwd c; lex stream >]
(* end of stream. *)
| [< >] -> [< >]
and lex_number buffer = parser
| [< ' ('0' .. '9' | '.' as c); stream >] ->
Buffer.add_char buffer c;
lex_number buffer stream
| [< stream=lex >] ->
[< 'Token.Number (float_of_string (Buffer.contents buffer)); stream >]
and lex_ident buffer = parser
| [< ' ('A' .. 'Z' | 'a' .. 'z' | '0' .. '9' as c); stream >] ->
Buffer.add_char buffer c;
lex_ident buffer stream
| [< stream=lex >] ->
match Buffer.contents buffer with
| "def" -> [< 'Token.Def; stream >]
| "extern" -> [< 'Token.Extern; stream >]
| "if" -> [< 'Token.If; stream >]
| "then" -> [< 'Token.Then; stream >]
| "else" -> [< 'Token.Else; stream >]
| "for" -> [< 'Token.For; stream >]
| "in" -> [< 'Token.In; stream >]
| "binary" -> [< 'Token.Binary; stream >]
| "unary" -> [< 'Token.Unary; stream >]
| "var" -> [< 'Token.Var; stream >]
| id -> [< 'Token.Ident id; stream >]
and lex_comment = parser
| [< ' ('\n'); stream=lex >] -> stream
| [< 'c; e=lex_comment >] -> e
| [< >] -> [< >]

View File

@ -0,0 +1,10 @@
open Ocamlbuild_plugin;;
ocaml_lib ~extern:true "llvm";;
ocaml_lib ~extern:true "llvm_analysis";;
ocaml_lib ~extern:true "llvm_executionengine";;
ocaml_lib ~extern:true "llvm_target";;
ocaml_lib ~extern:true "llvm_scalar_opts";;
flag ["link"; "ocaml"; "g++"] (S[A"-cc"; A"g++"]);;
dep ["link"; "ocaml"; "use_bindings"] ["bindings.o"];;

View File

@ -0,0 +1,221 @@
(*===---------------------------------------------------------------------===
* Parser
*===---------------------------------------------------------------------===*)
(* binop_precedence - This holds the precedence for each binary operator that is
* defined *)
let binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10
(* precedence - Get the precedence of the pending binary operator token. *)
let precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1
(* primary
* ::= identifier
* ::= numberexpr
* ::= parenexpr
* ::= ifexpr
* ::= forexpr
* ::= varexpr *)
let rec parse_primary = parser
(* numberexpr ::= number *)
| [< 'Token.Number n >] -> Ast.Number n
(* parenexpr ::= '(' expression ')' *)
| [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e
(* identifierexpr
* ::= identifier
* ::= identifier '(' argumentexpr ')' *)
| [< 'Token.Ident id; stream >] ->
let rec parse_args accumulator = parser
| [< e=parse_expr; stream >] ->
begin parser
| [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e
| [< >] -> e :: accumulator
end stream
| [< >] -> accumulator
in
let rec parse_ident id = parser
(* Call. *)
| [< 'Token.Kwd '(';
args=parse_args [];
'Token.Kwd ')' ?? "expected ')'">] ->
Ast.Call (id, Array.of_list (List.rev args))
(* Simple variable ref. *)
| [< >] -> Ast.Variable id
in
parse_ident id stream
(* ifexpr ::= 'if' expr 'then' expr 'else' expr *)
| [< 'Token.If; c=parse_expr;
'Token.Then ?? "expected 'then'"; t=parse_expr;
'Token.Else ?? "expected 'else'"; e=parse_expr >] ->
Ast.If (c, t, e)
(* forexpr
::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression *)
| [< 'Token.For;
'Token.Ident id ?? "expected identifier after for";
'Token.Kwd '=' ?? "expected '=' after for";
stream >] ->
begin parser
| [<
start=parse_expr;
'Token.Kwd ',' ?? "expected ',' after for";
end_=parse_expr;
stream >] ->
let step =
begin parser
| [< 'Token.Kwd ','; step=parse_expr >] -> Some step
| [< >] -> None
end stream
in
begin parser
| [< 'Token.In; body=parse_expr >] ->
Ast.For (id, start, end_, step, body)
| [< >] ->
raise (Stream.Error "expected 'in' after for")
end stream
| [< >] ->
raise (Stream.Error "expected '=' after for")
end stream
(* varexpr
* ::= 'var' identifier ('=' expression?
* (',' identifier ('=' expression)?)* 'in' expression *)
| [< 'Token.Var;
(* At least one variable name is required. *)
'Token.Ident id ?? "expected identifier after var";
init=parse_var_init;
var_names=parse_var_names [(id, init)];
(* At this point, we have to have 'in'. *)
'Token.In ?? "expected 'in' keyword after 'var'";
body=parse_expr >] ->
Ast.Var (Array.of_list (List.rev var_names), body)
| [< >] -> raise (Stream.Error "unknown token when expecting an expression.")
(* unary
* ::= primary
* ::= '!' unary *)
and parse_unary = parser
(* If this is a unary operator, read it. *)
| [< 'Token.Kwd op when op != '(' && op != ')'; operand=parse_expr >] ->
Ast.Unary (op, operand)
(* If the current token is not an operator, it must be a primary expr. *)
| [< stream >] -> parse_primary stream
(* binoprhs
* ::= ('+' primary)* *)
and parse_bin_rhs expr_prec lhs stream =
match Stream.peek stream with
(* If this is a binop, find its precedence. *)
| Some (Token.Kwd c) when Hashtbl.mem binop_precedence c ->
let token_prec = precedence c in
(* If this is a binop that binds at least as tightly as the current binop,
* consume it, otherwise we are done. *)
if token_prec < expr_prec then lhs else begin
(* Eat the binop. *)
Stream.junk stream;
(* Parse the primary expression after the binary operator. *)
let rhs = parse_unary stream in
(* Okay, we know this is a binop. *)
let rhs =
match Stream.peek stream with
| Some (Token.Kwd c2) ->
(* If BinOp binds less tightly with rhs than the operator after
* rhs, let the pending operator take rhs as its lhs. *)
let next_prec = precedence c2 in
if token_prec < next_prec
then parse_bin_rhs (token_prec + 1) rhs stream
else rhs
| _ -> rhs
in
(* Merge lhs/rhs. *)
let lhs = Ast.Binary (c, lhs, rhs) in
parse_bin_rhs expr_prec lhs stream
end
| _ -> lhs
and parse_var_init = parser
(* read in the optional initializer. *)
| [< 'Token.Kwd '='; e=parse_expr >] -> Some e
| [< >] -> None
and parse_var_names accumulator = parser
| [< 'Token.Kwd ',';
'Token.Ident id ?? "expected identifier list after var";
init=parse_var_init;
e=parse_var_names ((id, init) :: accumulator) >] -> e
| [< >] -> accumulator
(* expression
* ::= primary binoprhs *)
and parse_expr = parser
| [< lhs=parse_unary; stream >] -> parse_bin_rhs 0 lhs stream
(* prototype
* ::= 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";
args=parse_args [];
'Token.Kwd ')' ?? "expected ')' in 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")
(* definition ::= 'def' prototype expression *)
let parse_definition = parser
| [< 'Token.Def; p=parse_prototype; e=parse_expr >] ->
Ast.Function (p, e)
(* toplevelexpr ::= expression *)
let parse_toplevel = parser
| [< e=parse_expr >] ->
(* Make an anonymous proto. *)
Ast.Function (Ast.Prototype ("", [||]), e)
(* external ::= 'extern' prototype *)
let parse_extern = parser
| [< 'Token.Extern; e=parse_prototype >] -> e

View File

@ -0,0 +1,25 @@
(*===----------------------------------------------------------------------===
* Lexer Tokens
*===----------------------------------------------------------------------===*)
(* The lexer returns these 'Kwd' if it is an unknown character, otherwise one of
* these others for known things. *)
type token =
(* commands *)
| Def | Extern
(* primary *)
| Ident of string | Number of float
(* unknown *)
| Kwd of char
(* control *)
| If | Then | Else
| For | In
(* operators *)
| Binary | Unary
(* var definition *)
| Var

View File

@ -0,0 +1,49 @@
(*===----------------------------------------------------------------------===
* Top-Level parsing and JIT Driver
*===----------------------------------------------------------------------===*)
open Llvm
open Llvm_executionengine
(* top ::= definition | external | expression | ';' *)
let rec main_loop the_fpm the_execution_engine stream =
match Stream.peek stream with
| None -> ()
(* ignore top-level semicolons. *)
| Some (Token.Kwd ';') ->
Stream.junk stream;
main_loop the_fpm the_execution_engine stream
| Some token ->
begin
try match token with
| Token.Def ->
let e = Parser.parse_definition stream in
print_endline "parsed a function definition.";
dump_value (Codegen.codegen_func the_fpm e);
| Token.Extern ->
let e = Parser.parse_extern stream in
print_endline "parsed an extern.";
dump_value (Codegen.codegen_proto e);
| _ ->
(* Evaluate a top-level expression into an anonymous function. *)
let e = Parser.parse_toplevel stream in
print_endline "parsed a top-level expr";
let the_function = Codegen.codegen_func the_fpm e in
dump_value the_function;
(* JIT the function, returning a function pointer. *)
let result = ExecutionEngine.run_function the_function [||]
the_execution_engine in
print_string "Evaluated to ";
print_float (GenericValue.as_float Codegen.double_type result);
print_newline ();
with Stream.Error s | Codegen.Error s ->
(* Skip token for error recovery. *)
Stream.junk stream;
print_endline s;
end;
print_string "ready> "; flush stdout;
main_loop the_fpm the_execution_engine stream

View File

@ -0,0 +1,57 @@
(*===----------------------------------------------------------------------===
* Main driver code.
*===----------------------------------------------------------------------===*)
open Llvm
open Llvm_executionengine
open Llvm_target
open Llvm_scalar_opts
let main () =
ignore (initialize_native_target ());
(* Install standard binary operators.
* 1 is the lowest precedence. *)
Hashtbl.add Parser.binop_precedence '=' 2;
Hashtbl.add Parser.binop_precedence '<' 10;
Hashtbl.add Parser.binop_precedence '+' 20;
Hashtbl.add Parser.binop_precedence '-' 20;
Hashtbl.add Parser.binop_precedence '*' 40; (* highest. *)
(* Prime the first token. *)
print_string "ready> "; flush stdout;
let stream = Lexer.lex (Stream.of_channel stdin) in
(* Create the JIT. *)
let the_execution_engine = ExecutionEngine.create Codegen.the_module in
let the_fpm = PassManager.create_function Codegen.the_module in
(* Set up the optimizer pipeline. Start with registering info about how the
* target lays out data structures. *)
TargetData.add (ExecutionEngine.target_data the_execution_engine) the_fpm;
(* Promote allocas to registers. *)
add_memory_to_register_promotion the_fpm;
(* Do simple "peephole" optimizations and bit-twiddling optzn. *)
add_instruction_combination the_fpm;
(* reassociate expressions. *)
add_reassociation the_fpm;
(* Eliminate Common SubExpressions. *)
add_gvn the_fpm;
(* Simplify the control flow graph (deleting unreachable blocks, etc). *)
add_cfg_simplification the_fpm;
ignore (PassManager.initialize the_fpm);
(* Run the main "interpreter loop" now. *)
Toplevel.main_loop the_fpm the_execution_engine stream;
(* Print out all the generated code. *)
dump_module Codegen.the_module
;;
main ()

View File

@ -0,0 +1,15 @@
##===- examples/OCaml-Kaleidoscope/Makefile ----------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL=../..
include $(LEVEL)/Makefile.config
PARALLEL_DIRS:= Chapter2 Chapter3 Chapter4 Chapter5 Chapter6 Chapter7
include $(LEVEL)/Makefile.common