Bladeren bron

Started on implementing CiviC compiler

Taddeus Kroes 12 jaren geleden
commit
ee11dce399
22 gewijzigde bestanden met toevoegingen van 2068 en 0 verwijderingen
  1. 11 0
      .gitignore
  2. 19 0
      Makefile
  3. 1299 0
      OCamlMakefile
  4. 85 0
      ast.ml
  5. BIN
      bin32/civas
  6. BIN
      bin32/civcc
  7. BIN
      bin32/civvm
  8. BIN
      doc/milestones.pdf
  9. BIN
      doc/project.pdf
  10. 88 0
      lexer.mll
  11. 41 0
      main.ml
  12. 149 0
      parser.mly
  13. 29 0
      phases/desug.ml
  14. 37 0
      phases/parse.ml
  15. 13 0
      phases/print.ml
  16. 140 0
      stringify.ml
  17. 1 0
      stringify.mli
  18. 27 0
      test/array_init.cvc
  19. 39 0
      test/test.cvc
  20. 3 0
      test/var_init.cvc
  21. 86 0
      trav.ml
  22. 1 0
      trav.mli

+ 11 - 0
.gitignore

@@ -0,0 +1,11 @@
+._*/
+civicc
+*.out
+*.cmo
+*.cmi
+*.cmx
+*.swp
+*.o
+lexer.ml
+parser.ml
+parser.mli

+ 19 - 0
Makefile

@@ -0,0 +1,19 @@
+RESULT := civicc
+SOURCES := ast.ml lexer.mll parser.mly trav.mli trav.ml stringify.mli \
+	stringify.ml \
+	phases/parse.ml  phases/print.ml phases/desug.ml \
+	main.ml
+PRE_TARGETS := ast.cmi
+
+OCAMLYACC := menhir
+YFLAGS := --infer
+
+all: native-code
+
+clean:: myclean
+
+.PHONY: myclean
+myclean:
+	rm -f a.out
+
+include OCamlMakefile

+ 1299 - 0
OCamlMakefile

@@ -0,0 +1,1299 @@
+###########################################################################
+#                              OCamlMakefile
+#                  Copyright (C) 1999-  Markus Mottl
+#
+#                             For updates see:
+#                http://www.ocaml.info/home/ocaml_sources.html
+#
+###########################################################################
+
+# Modified by damien for .glade.ml compilation
+
+# Set these variables to the names of the sources to be processed and
+# the result variable. Order matters during linkage!
+
+ifndef SOURCES
+  SOURCES := foo.ml
+endif
+export SOURCES
+
+ifndef RES_CLIB_SUF
+  RES_CLIB_SUF := _stubs
+endif
+export RES_CLIB_SUF
+
+ifndef RESULT
+  RESULT := foo
+endif
+export RESULT := $(strip $(RESULT))
+
+export LIB_PACK_NAME
+
+ifndef DOC_FILES
+  DOC_FILES := $(filter %.mli, $(SOURCES))
+endif
+export DOC_FILES
+FIRST_DOC_FILE := $(firstword $(DOC_FILES))
+
+export BCSUFFIX
+export NCSUFFIX
+
+ifndef TOPSUFFIX
+  TOPSUFFIX := .top
+endif
+export TOPSUFFIX
+
+# Eventually set include- and library-paths, libraries to link,
+# additional compilation-, link- and ocamlyacc-flags
+# Path- and library information needs not be written with "-I" and such...
+# Define THREADS if you need it, otherwise leave it unset (same for
+# USE_CAMLP4)!
+
+export THREADS
+export VMTHREADS
+export ANNOTATE
+export USE_CAMLP4
+
+export INCDIRS
+export LIBDIRS
+export EXTLIBDIRS
+export RESULTDEPS
+export OCAML_DEFAULT_DIRS
+
+export LIBS
+export CLIBS
+export CFRAMEWORKS
+
+export OCAMLFLAGS
+export OCAMLNCFLAGS
+export OCAMLBCFLAGS
+
+export OCAMLLDFLAGS
+export OCAMLNLDFLAGS
+export OCAMLBLDFLAGS
+
+export OCAMLMKLIB_FLAGS
+
+ifndef OCAMLCPFLAGS
+  OCAMLCPFLAGS := a
+endif
+export OCAMLCPFLAGS
+
+ifndef DOC_DIR
+  DOC_DIR := doc
+endif
+export DOC_DIR
+
+export PPFLAGS
+
+export LFLAGS
+export YFLAGS
+export IDLFLAGS
+
+export OCAMLDOCFLAGS
+
+export OCAMLFIND_INSTFLAGS
+
+export DVIPSFLAGS
+
+export STATIC
+
+# Add a list of optional trash files that should be deleted by "make clean"
+export TRASH
+
+ECHO := echo
+
+ifdef REALLY_QUIET
+  export REALLY_QUIET
+  ECHO := true
+  LFLAGS := $(LFLAGS) -q
+  YFLAGS := $(YFLAGS) -q
+endif
+
+####################  variables depending on your OCaml-installation
+
+SYSTEM := $(shell ocamlc -config 2>/dev/null | grep system | sed 's/system: //')
+    # This may be
+    # - mingw
+    # - mingw64
+    # - win32
+    # - cygwin
+    # - some other string means Unix
+    # - empty means ocamlc does not support -config
+
+ifeq ($(SYSTEM),$(filter $(SYSTEM),mingw mingw64))
+  MINGW=1
+endif
+ifeq ($(SYSTEM),win32)
+  MSVC=1
+endif
+
+ifdef MINGW
+  export MINGW
+  WIN32 := 1
+  # The default value 'cc' makes 'ocamlc -cc "cc"' raises the error 'The
+  # NTVDM CPU has encountered an illegal instruction'.
+  ifndef CC
+    MNO_CYGWIN := $(shell gcc -Wextra -v --help 2>/dev/null | grep -q '\-mno-cygwin'; echo $$?)
+    CC := gcc
+  else
+    MNO_CYGWIN := $(shell $$CC -Wextra -v --help 2>/dev/null | grep -q '\-mno-cygwin'; echo $$?)
+  endif
+  # We are compiling with cygwin tools:
+  ifeq ($(MNO_CYGWIN),0)
+	CFLAGS_WIN32 := -mno-cygwin
+  endif
+  # The OCaml C header files use this flag:
+  CFLAGS += -D__MINGW32__
+endif
+ifdef MSVC
+  export MSVC
+  WIN32   := 1
+  ifndef STATIC
+    CPPFLAGS_WIN32 := -DCAML_DLL
+  endif
+  CFLAGS_WIN32 += -nologo
+  EXT_OBJ := obj
+  EXT_LIB := lib
+  ifeq ($(CC),gcc)
+    # work around GNU Make default value
+    ifdef THREADS
+      CC := cl -MT
+    else
+      CC := cl
+    endif
+  endif
+  ifeq ($(CXX),g++)
+    # work around GNU Make default value
+    CXX := $(CC)
+  endif
+  CFLAG_O := -Fo
+endif
+ifdef WIN32
+  EXT_CXX := cpp
+  EXE     := .exe
+endif
+
+ifndef EXT_OBJ
+  EXT_OBJ := o
+endif
+ifndef EXT_LIB
+  EXT_LIB := a
+endif
+ifndef EXT_CXX
+  EXT_CXX := cc
+endif
+ifndef EXE
+  EXE := # empty
+endif
+ifndef CFLAG_O
+  CFLAG_O := -o # do not delete this comment (preserves trailing whitespace)!
+endif
+
+export CC
+export CXX
+export CFLAGS
+export CXXFLAGS
+export LDFLAGS
+export CPPFLAGS
+
+ifndef RPATH_FLAG
+  ifdef ELF_RPATH_FLAG
+    RPATH_FLAG := $(ELF_RPATH_FLAG)
+  else
+    RPATH_FLAG := -R
+  endif
+endif
+export RPATH_FLAG
+
+ifndef MSVC
+ifndef PIC_CFLAGS
+  PIC_CFLAGS := -fPIC
+endif
+ifndef PIC_CPPFLAGS
+  PIC_CPPFLAGS := -DPIC
+endif
+endif
+
+export PIC_CFLAGS
+export PIC_CPPFLAGS
+
+BCRESULT  := $(addsuffix $(BCSUFFIX), $(RESULT))
+NCRESULT  := $(addsuffix $(NCSUFFIX), $(RESULT))
+TOPRESULT := $(addsuffix $(TOPSUFFIX), $(RESULT))
+
+ifndef OCAMLFIND
+  OCAMLFIND := ocamlfind
+endif
+export OCAMLFIND
+
+ifndef OCAML
+  OCAML := ocaml
+endif
+export OCAML
+
+ifndef OCAMLC
+  OCAMLC := ocamlc
+endif
+export OCAMLC
+
+ifndef OCAMLOPT
+  OCAMLOPT := ocamlopt
+endif
+export OCAMLOPT
+
+ifndef OCAMLMKTOP
+  OCAMLMKTOP := ocamlmktop
+endif
+export OCAMLMKTOP
+
+ifndef OCAMLCP
+  OCAMLCP := ocamlcp
+endif
+export OCAMLCP
+
+ifndef OCAMLDEP
+  OCAMLDEP := ocamldep
+endif
+export OCAMLDEP
+
+ifndef OCAMLLEX
+  OCAMLLEX := ocamllex
+endif
+export OCAMLLEX
+
+ifndef OCAMLYACC
+  OCAMLYACC := ocamlyacc
+endif
+export OCAMLYACC
+
+ifndef OCAMLMKLIB
+  OCAMLMKLIB := ocamlmklib
+endif
+export OCAMLMKLIB
+
+ifndef OCAML_GLADECC
+  OCAML_GLADECC := lablgladecc2
+endif
+export OCAML_GLADECC
+
+ifndef OCAML_GLADECC_FLAGS
+  OCAML_GLADECC_FLAGS :=
+endif
+export OCAML_GLADECC_FLAGS
+
+ifndef CAMELEON_REPORT
+  CAMELEON_REPORT := report
+endif
+export CAMELEON_REPORT
+
+ifndef CAMELEON_REPORT_FLAGS
+  CAMELEON_REPORT_FLAGS :=
+endif
+export CAMELEON_REPORT_FLAGS
+
+ifndef CAMELEON_ZOGGY
+  CAMELEON_ZOGGY := camlp4o pa_zog.cma pr_o.cmo
+endif
+export CAMELEON_ZOGGY
+
+ifndef CAMELEON_ZOGGY_FLAGS
+  CAMELEON_ZOGGY_FLAGS :=
+endif
+export CAMELEON_ZOGGY_FLAGS
+
+ifndef OXRIDL
+  OXRIDL := oxridl
+endif
+export OXRIDL
+
+ifndef CAMLIDL
+  CAMLIDL := camlidl
+endif
+export CAMLIDL
+
+ifndef CAMLIDLDLL
+  CAMLIDLDLL := camlidldll
+endif
+export CAMLIDLDLL
+
+ifndef NOIDLHEADER
+  MAYBE_IDL_HEADER := -header
+endif
+export NOIDLHEADER
+
+export NO_CUSTOM
+
+ifndef CAMLP4
+  CAMLP4 := camlp4
+endif
+export CAMLP4
+
+ifndef REAL_OCAMLFIND
+  ifdef PACKS
+    ifndef CREATE_LIB
+      ifdef THREADS
+	PACKS += threads
+      endif
+    endif
+    empty :=
+    space := $(empty) $(empty)
+    comma := ,
+    ifdef PREDS
+      PRE_OCAML_FIND_PREDICATES := $(subst $(space),$(comma),$(PREDS))
+      PRE_OCAML_FIND_PACKAGES := $(subst $(space),$(comma),$(PACKS))
+      OCAML_FIND_PREDICATES := -predicates $(PRE_OCAML_FIND_PREDICATES)
+  #    OCAML_DEP_PREDICATES := -syntax $(PRE_OCAML_FIND_PREDICATES)
+      OCAML_FIND_PACKAGES := $(OCAML_FIND_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES)
+      OCAML_DEP_PACKAGES := $(OCAML_DEP_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES)
+    else
+      OCAML_FIND_PACKAGES := -package $(subst $(space),$(comma),$(PACKS))
+      OCAML_DEP_PACKAGES :=
+    endif
+    OCAML_FIND_LINKPKG := -linkpkg
+    REAL_OCAMLFIND := $(OCAMLFIND)
+  endif
+endif
+
+export OCAML_FIND_PACKAGES
+export OCAML_DEP_PACKAGES
+export OCAML_FIND_LINKPKG
+export REAL_OCAMLFIND
+
+ifndef OCAMLDOC
+  OCAMLDOC := ocamldoc
+endif
+export OCAMLDOC
+
+ifndef LATEX
+  LATEX := latex
+endif
+export LATEX
+
+ifndef DVIPS
+  DVIPS := dvips
+endif
+export DVIPS
+
+ifndef PS2PDF
+  PS2PDF := ps2pdf
+endif
+export PS2PDF
+
+ifndef OCAMLMAKEFILE
+  OCAMLMAKEFILE := OCamlMakefile
+endif
+export OCAMLMAKEFILE
+
+ifndef OCAMLLIBPATH
+  OCAMLLIBPATH := \
+    $(shell $(OCAMLC) 2>/dev/null -where || echo /usr/local/lib/ocaml)
+endif
+export OCAMLLIBPATH
+
+ifndef OCAML_LIB_INSTALL
+  OCAML_LIB_INSTALL := $(OCAMLLIBPATH)/contrib
+endif
+export OCAML_LIB_INSTALL
+
+###########################################################################
+
+####################  change following sections only if
+####################    you know what you are doing!
+
+# delete target files when a build command fails
+.PHONY: .DELETE_ON_ERROR
+.DELETE_ON_ERROR:
+
+# for pedants using "--warn-undefined-variables"
+export MAYBE_IDL
+export REAL_RESULT
+export CAMLIDLFLAGS
+export THREAD_FLAG
+export RES_CLIB
+export MAKEDLL
+export ANNOT_FLAG
+export C_OXRIDL
+export SUBPROJS
+export CFLAGS_WIN32
+export CPPFLAGS_WIN32
+
+INCFLAGS :=
+
+SHELL := /bin/sh
+
+MLDEPDIR := ._d
+BCDIDIR  := ._bcdi
+NCDIDIR  := ._ncdi
+
+FILTER_EXTNS := %.mli %.ml %.mll %.mly %.idl %.oxridl %.c %.m %.$(EXT_CXX) %.rep %.zog %.glade
+
+FILTERED     := $(filter $(FILTER_EXTNS), $(SOURCES))
+SOURCE_DIRS  := $(filter-out ./, $(sort $(dir $(FILTERED))))
+
+FILTERED_REP := $(filter %.rep, $(FILTERED))
+DEP_REP      := $(FILTERED_REP:%.rep=$(MLDEPDIR)/%.d)
+AUTO_REP     := $(FILTERED_REP:.rep=.ml)
+
+FILTERED_ZOG := $(filter %.zog, $(FILTERED))
+DEP_ZOG      := $(FILTERED_ZOG:%.zog=$(MLDEPDIR)/%.d)
+AUTO_ZOG     := $(FILTERED_ZOG:.zog=.ml)
+
+FILTERED_GLADE := $(filter %.glade, $(FILTERED))
+DEP_GLADE      := $(FILTERED_GLADE:%.glade=$(MLDEPDIR)/%.d)
+AUTO_GLADE     := $(FILTERED_GLADE:.glade=.ml)
+
+FILTERED_ML  := $(filter %.ml, $(FILTERED))
+DEP_ML       := $(FILTERED_ML:%.ml=$(MLDEPDIR)/%.d)
+
+FILTERED_MLI := $(filter %.mli, $(FILTERED))
+DEP_MLI      := $(FILTERED_MLI:.mli=.di)
+
+FILTERED_MLL := $(filter %.mll, $(FILTERED))
+DEP_MLL      := $(FILTERED_MLL:%.mll=$(MLDEPDIR)/%.d)
+AUTO_MLL     := $(FILTERED_MLL:.mll=.ml)
+
+FILTERED_MLY := $(filter %.mly, $(FILTERED))
+DEP_MLY      := $(FILTERED_MLY:%.mly=$(MLDEPDIR)/%.d) $(FILTERED_MLY:.mly=.di)
+AUTO_MLY     := $(FILTERED_MLY:.mly=.mli) $(FILTERED_MLY:.mly=.ml)
+
+FILTERED_IDL := $(filter %.idl, $(FILTERED))
+DEP_IDL      := $(FILTERED_IDL:%.idl=$(MLDEPDIR)/%.d) $(FILTERED_IDL:.idl=.di)
+C_IDL        := $(FILTERED_IDL:%.idl=%_stubs.c)
+ifndef NOIDLHEADER
+ C_IDL += $(FILTERED_IDL:.idl=.h)
+endif
+OBJ_C_IDL    := $(FILTERED_IDL:%.idl=%_stubs.$(EXT_OBJ))
+AUTO_IDL     := $(FILTERED_IDL:.idl=.mli) $(FILTERED_IDL:.idl=.ml) $(C_IDL)
+
+FILTERED_OXRIDL := $(filter %.oxridl, $(FILTERED))
+DEP_OXRIDL      := $(FILTERED_OXRIDL:%.oxridl=$(MLDEPDIR)/%.d) $(FILTERED_OXRIDL:.oxridl=.di)
+AUTO_OXRIDL     := $(FILTERED_OXRIDL:.oxridl=.mli) $(FILTERED_OXRIDL:.oxridl=.ml) $(C_OXRIDL)
+
+FILTERED_C_CXX := $(filter %.c %.m %.$(EXT_CXX), $(FILTERED))
+OBJ_C_CXX      := $(FILTERED_C_CXX:.c=.$(EXT_OBJ))
+OBJ_C_CXX      := $(OBJ_C_CXX:.m=.$(EXT_OBJ))
+OBJ_C_CXX      := $(OBJ_C_CXX:.$(EXT_CXX)=.$(EXT_OBJ))
+
+PRE_TARGETS  += $(AUTO_MLL) $(AUTO_MLY) $(AUTO_IDL) $(AUTO_OXRIDL) $(AUTO_ZOG) $(AUTO_REP) $(AUTO_GLADE)
+
+ALL_DEPS     := $(DEP_ML) $(DEP_MLI) $(DEP_MLL) $(DEP_MLY) $(DEP_IDL) $(DEP_OXRIDL) $(DEP_ZOG) $(DEP_REP) $(DEP_GLADE)
+
+MLDEPS       := $(filter %.d, $(ALL_DEPS))
+MLIDEPS      := $(filter %.di, $(ALL_DEPS))
+BCDEPIS      := $(MLIDEPS:%.di=$(BCDIDIR)/%.di)
+NCDEPIS      := $(MLIDEPS:%.di=$(NCDIDIR)/%.di)
+
+ALLML        := $(filter %.mli %.ml %.mll %.mly %.idl %.oxridl %.rep %.zog %.glade, $(FILTERED))
+
+IMPLO_INTF   := $(ALLML:%.mli=%.mli.__)
+IMPLO_INTF   := $(foreach file, $(IMPLO_INTF), \
+                  $(basename $(file)).cmi $(basename $(file)).cmo)
+IMPLO_INTF   := $(filter-out %.mli.cmo, $(IMPLO_INTF))
+IMPLO_INTF   := $(IMPLO_INTF:%.mli.cmi=%.cmi)
+
+IMPLX_INTF   := $(IMPLO_INTF:.cmo=.cmx)
+
+INTF         := $(filter %.cmi, $(IMPLO_INTF))
+IMPL_CMO     := $(filter %.cmo, $(IMPLO_INTF))
+IMPL_CMX     := $(IMPL_CMO:.cmo=.cmx)
+IMPL_ASM     := $(IMPL_CMO:.cmo=.asm)
+IMPL_S       := $(IMPL_CMO:.cmo=.s)
+
+OBJ_LINK     := $(OBJ_C_IDL) $(OBJ_C_CXX)
+OBJ_FILES    := $(IMPL_CMO:.cmo=.$(EXT_OBJ)) $(OBJ_LINK)
+
+EXECS        := $(addsuffix $(EXE), \
+                            $(sort $(TOPRESULT) $(BCRESULT) $(NCRESULT)))
+ifdef WIN32
+  EXECS      += $(BCRESULT).dll $(NCRESULT).dll
+endif
+
+CLIB_BASE    := $(RESULT)$(RES_CLIB_SUF)
+ifneq ($(strip $(OBJ_LINK)),)
+  RES_CLIB     := lib$(CLIB_BASE).$(EXT_LIB)
+endif
+
+ifdef WIN32
+DLLSONAME := dll$(CLIB_BASE).dll
+else
+DLLSONAME := dll$(CLIB_BASE).so
+endif
+
+NONEXECS     := $(INTF) $(IMPL_CMO) $(IMPL_CMX) $(IMPL_ASM) $(IMPL_S) \
+		$(OBJ_FILES) $(PRE_TARGETS) $(BCRESULT).cma $(NCRESULT).cmxa \
+		$(NCRESULT).$(EXT_LIB) $(BCRESULT).cmi $(BCRESULT).cmo \
+		$(NCRESULT).cmi $(NCRESULT).cmx $(NCRESULT).$(EXT_OBJ) \
+		$(RES_CLIB) $(IMPL_CMO:.cmo=.annot) \
+		$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(LIB_PACK_NAME).cmx \
+		$(LIB_PACK_NAME).$(EXT_OBJ)
+
+ifndef STATIC
+  NONEXECS += $(DLLSONAME)
+endif
+
+ifndef LIBINSTALL_FILES
+  LIBINSTALL_FILES := $(RESULT).mli $(RESULT).cmi $(RESULT).cma \
+		      $(RESULT).cmxa $(RESULT).$(EXT_LIB) $(RES_CLIB)
+  ifndef STATIC
+    ifneq ($(strip $(OBJ_LINK)),)
+      LIBINSTALL_FILES += $(DLLSONAME)
+    endif
+  endif
+endif
+
+export LIBINSTALL_FILES
+
+ifdef WIN32
+  # some extra stuff is created while linking DLLs
+  NONEXECS   += $(BCRESULT).$(EXT_LIB) $(BCRESULT).exp $(NCRESULT).exp $(CLIB_BASE).exp $(CLIB_BASE).lib
+endif
+
+TARGETS      := $(EXECS) $(NONEXECS)
+
+# If there are IDL-files
+ifneq ($(strip $(FILTERED_IDL)),)
+  MAYBE_IDL := -cclib -lcamlidl
+endif
+
+ifdef USE_CAMLP4
+  CAMLP4PATH := \
+    $(shell $(CAMLP4) -where 2>/dev/null || echo /usr/local/lib/camlp4)
+  INCFLAGS := -I $(CAMLP4PATH)
+  CINCFLAGS := -I$(CAMLP4PATH)
+endif
+
+INCFLAGS := $(INCFLAGS) $(INCDIRS:%=-I %) $(SOURCE_DIRS:%=-I %) $(OCAML_DEFAULT_DIRS:%=-I %)
+CINCFLAGS += $(SOURCE_DIRS:%=-I%) $(INCDIRS:%=-I%) $(OCAML_DEFAULT_DIRS:%=-I%)
+
+ifndef MSVC
+  CLIBFLAGS += $(SOURCE_DIRS:%=-L%) $(LIBDIRS:%=-L%) \
+               $(EXTLIBDIRS:%=-L%) $(OCAML_DEFAULT_DIRS:%=-L%)
+
+  ifeq ($(ELF_RPATH), yes)
+    CLIBFLAGS += $(EXTLIBDIRS:%=-Wl,$(RPATH_FLAG)%)
+  endif
+endif
+
+ifndef PROFILING
+  INTF_OCAMLC := $(OCAMLC)
+else
+  ifndef THREADS
+    INTF_OCAMLC := $(OCAMLCP) -p $(OCAMLCPFLAGS)
+  else
+    # OCaml does not support profiling byte code
+    # with threads (yet), therefore we force an error.
+    ifndef REAL_OCAMLC
+      $(error Profiling of multithreaded byte code not yet supported by OCaml)
+    endif
+    INTF_OCAMLC := $(OCAMLC)
+  endif
+endif
+
+ifndef MSVC
+  COMMON_LDFLAGS := $(LDFLAGS:%=-ccopt %) $(SOURCE_DIRS:%=-ccopt -L%) \
+		    $(LIBDIRS:%=-ccopt -L%) $(EXTLIBDIRS:%=-ccopt -L%) \
+		    $(EXTLIBDIRS:%=-ccopt -Wl $(OCAML_DEFAULT_DIRS:%=-ccopt -L%))
+
+  ifeq ($(ELF_RPATH),yes)
+    COMMON_LDFLAGS += $(EXTLIBDIRS:%=-ccopt -Wl,$(RPATH_FLAG)%)
+  endif
+else
+  COMMON_LDFLAGS := -ccopt "/link -NODEFAULTLIB:LIBC $(LDFLAGS:%=%) $(SOURCE_DIRS:%=-LIBPATH:%) \
+		    $(LIBDIRS:%=-LIBPATH:%) $(EXTLIBDIRS:%=-LIBPATH:%) \
+		    $(OCAML_DEFAULT_DIRS:%=-LIBPATH:%) "
+endif
+
+CLIBS_OPTS := $(CLIBS:%=-cclib -l%) $(CFRAMEWORKS:%=-cclib '-framework %')
+ifdef MSVC
+  ifndef STATIC
+  # MSVC libraries do not have 'lib' prefix
+  CLIBS_OPTS := $(CLIBS:%=-cclib %.lib)
+  endif
+endif
+
+ifneq ($(strip $(OBJ_LINK)),)
+  ifdef CREATE_LIB
+    OBJS_LIBS := -cclib -l$(CLIB_BASE) $(CLIBS_OPTS) $(MAYBE_IDL)
+  else
+    OBJS_LIBS := $(OBJ_LINK) $(CLIBS_OPTS) $(MAYBE_IDL)
+  endif
+else
+  OBJS_LIBS := $(CLIBS_OPTS) $(MAYBE_IDL)
+endif
+
+ifdef LIB_PACK_NAME
+  FOR_PACK_NAME := $(shell echo $(LIB_PACK_NAME) | awk '{print toupper(substr($$0,1,1))substr($$0,2)}')
+endif
+
+# If we have to make byte-code
+ifndef REAL_OCAMLC
+  BYTE_OCAML := y
+
+  # EXTRADEPS is added dependencies we have to insert for all
+  # executable files we generate.  Ideally it should be all of the
+  # libraries we use, but it's hard to find the ones that get searched on
+  # the path since I don't know the paths built into the compiler, so
+  # just include the ones with slashes in their names.
+  EXTRADEPS := $(addsuffix .cma,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i))))
+
+
+  ifndef LIB_PACK_NAME
+    SPECIAL_OCAMLFLAGS := $(OCAMLBCFLAGS)
+  else
+    SPECIAL_OCAMLFLAGS := -for-pack $(FOR_PACK_NAME) $(OCAMLBCFLAGS)
+  endif
+
+  REAL_OCAMLC := $(INTF_OCAMLC)
+
+  REAL_IMPL := $(IMPL_CMO)
+  REAL_IMPL_INTF := $(IMPLO_INTF)
+  IMPL_SUF := .cmo
+
+  DEPFLAGS  :=
+  MAKE_DEPS := $(MLDEPS) $(BCDEPIS)
+
+  ifdef CREATE_LIB
+    override CFLAGS := $(PIC_CFLAGS) $(CFLAGS)
+    override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS)
+    ifndef STATIC
+      ifneq ($(strip $(OBJ_LINK)),)
+	MAKEDLL := $(DLLSONAME)
+	ALL_LDFLAGS := -dllib $(DLLSONAME)
+      endif
+    endif
+  endif
+
+  ifndef NO_CUSTOM
+    ifneq "$(strip $(OBJ_LINK) $(THREADS) $(MAYBE_IDL) $(CLIBS) $(CFRAMEWORKS))" ""
+      ALL_LDFLAGS += -custom
+    endif
+  endif
+
+  ALL_LDFLAGS += $(INCFLAGS) $(OCAMLLDFLAGS) $(OCAMLBLDFLAGS) \
+                 $(COMMON_LDFLAGS) $(LIBS:%=%.cma)
+  CAMLIDLDLLFLAGS :=
+
+  ifdef THREADS
+    ifdef VMTHREADS
+      THREAD_FLAG := -vmthread
+    else
+      THREAD_FLAG := -thread
+    endif
+    ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS)
+    ifndef CREATE_LIB
+      ifndef REAL_OCAMLFIND
+        ALL_LDFLAGS := unix.cma threads.cma $(ALL_LDFLAGS)
+      endif
+    endif
+  endif
+
+# we have to make native-code
+else
+  EXTRADEPS := $(addsuffix .cmxa,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i))))
+  ifndef PROFILING
+    SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS)
+    PLDFLAGS :=
+  else
+    SPECIAL_OCAMLFLAGS := -p $(OCAMLNCFLAGS)
+    PLDFLAGS := -p
+  endif
+
+  ifndef LIB_PACK_NAME
+    SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS)
+  else
+    SPECIAL_OCAMLFLAGS := -for-pack $(FOR_PACK_NAME) $(OCAMLNCFLAGS)
+  endif
+  REAL_IMPL := $(IMPL_CMX)
+  REAL_IMPL_INTF := $(IMPLX_INTF)
+  IMPL_SUF := .cmx
+
+  override CPPFLAGS := -DNATIVE_CODE $(CPPFLAGS)
+
+  DEPFLAGS  := -native
+  MAKE_DEPS := $(MLDEPS) $(NCDEPIS)
+
+  ALL_LDFLAGS := $(PLDFLAGS) $(INCFLAGS) $(OCAMLLDFLAGS) \
+                 $(OCAMLNLDFLAGS) $(COMMON_LDFLAGS)
+  CAMLIDLDLLFLAGS := -opt
+
+  ifndef CREATE_LIB
+    ALL_LDFLAGS += $(LIBS:%=%.cmxa)
+  else
+    override CFLAGS := $(PIC_CFLAGS) $(CFLAGS)
+    override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS)
+  endif
+
+  ifdef THREADS
+    THREAD_FLAG := -thread
+    ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS)
+    ifndef CREATE_LIB
+      ifndef REAL_OCAMLFIND
+        ALL_LDFLAGS := unix.cmxa threads.cmxa $(ALL_LDFLAGS)
+      endif
+    endif
+  endif
+endif
+
+export MAKE_DEPS
+
+ifdef ANNOTATE
+  ANNOT_FLAG := -annot
+else
+endif
+
+ALL_OCAMLCFLAGS := $(THREAD_FLAG) $(ANNOT_FLAG) $(OCAMLFLAGS) \
+                   $(INCFLAGS) $(SPECIAL_OCAMLFLAGS)
+
+ifdef make_deps
+  -include $(MAKE_DEPS)
+  PRE_TARGETS :=
+endif
+
+###########################################################################
+# USER RULES
+
+# Call "OCamlMakefile QUIET=" to get rid of all of the @'s.
+QUIET=@
+
+# generates byte-code (default)
+byte-code:		$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \
+				REAL_RESULT="$(BCRESULT)" make_deps=yes
+bc:	byte-code
+
+byte-code-nolink:	$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
+				REAL_RESULT="$(BCRESULT)" make_deps=yes
+bcnl:	byte-code-nolink
+
+top:			$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(TOPRESULT) \
+				REAL_RESULT="$(BCRESULT)" make_deps=yes
+
+# generates native-code
+
+native-code:		$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \
+				REAL_RESULT="$(NCRESULT)" \
+				REAL_OCAMLC="$(OCAMLOPT)" \
+				make_deps=yes
+nc:	native-code
+
+native-code-nolink:	$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
+				REAL_RESULT="$(NCRESULT)" \
+				REAL_OCAMLC="$(OCAMLOPT)" \
+				make_deps=yes
+ncnl:	native-code-nolink
+
+# generates byte-code libraries
+byte-code-library:	$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+				$(RES_CLIB) $(BCRESULT).cma \
+				REAL_RESULT="$(BCRESULT)" \
+				CREATE_LIB=yes \
+				make_deps=yes
+bcl:	byte-code-library
+
+# generates native-code libraries
+native-code-library:	$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+				$(RES_CLIB) $(NCRESULT).cmxa \
+				REAL_RESULT="$(NCRESULT)" \
+				REAL_OCAMLC="$(OCAMLOPT)" \
+				CREATE_LIB=yes \
+				make_deps=yes
+ncl:	native-code-library
+
+ifdef WIN32
+# generates byte-code dll
+byte-code-dll:		$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+				$(RES_CLIB) $(BCRESULT).dll \
+				REAL_RESULT="$(BCRESULT)" \
+				make_deps=yes
+bcd:	byte-code-dll
+
+# generates native-code dll
+native-code-dll:	$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+				$(RES_CLIB) $(NCRESULT).dll \
+				REAL_RESULT="$(NCRESULT)" \
+				REAL_OCAMLC="$(OCAMLOPT)" \
+				make_deps=yes
+ncd:	native-code-dll
+endif
+
+# generates byte-code with debugging information
+debug-code:		$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \
+				REAL_RESULT="$(BCRESULT)" make_deps=yes \
+				OCAMLFLAGS="-g $(OCAMLFLAGS)" \
+				OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
+dc:	debug-code
+
+debug-code-nolink:	$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
+				REAL_RESULT="$(BCRESULT)" make_deps=yes \
+				OCAMLFLAGS="-g $(OCAMLFLAGS)" \
+				OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
+dcnl:	debug-code-nolink
+
+# generates byte-code with debugging information (native code)
+debug-native-code:	$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \
+				REAL_RESULT="$(NCRESULT)" make_deps=yes \
+				REAL_OCAMLC="$(OCAMLOPT)" \
+				OCAMLFLAGS="-g $(OCAMLFLAGS)" \
+				OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
+dnc:	debug-native-code
+
+debug-native-code-nolink:	$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
+				REAL_RESULT="$(NCRESULT)" make_deps=yes \
+				REAL_OCAMLC="$(OCAMLOPT)" \
+				OCAMLFLAGS="-g $(OCAMLFLAGS)" \
+				OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
+dncnl:	debug-native-code-nolink
+
+# generates byte-code libraries with debugging information
+debug-code-library:	$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+				$(RES_CLIB) $(BCRESULT).cma \
+				REAL_RESULT="$(BCRESULT)" make_deps=yes \
+				CREATE_LIB=yes \
+				OCAMLFLAGS="-g $(OCAMLFLAGS)" \
+				OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
+dcl:	debug-code-library
+
+# generates byte-code libraries with debugging information (native code)
+debug-native-code-library:	$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+				$(RES_CLIB) $(NCRESULT).cmxa \
+				REAL_RESULT="$(NCRESULT)" make_deps=yes \
+				REAL_OCAMLC="$(OCAMLOPT)" \
+				CREATE_LIB=yes \
+				OCAMLFLAGS="-g $(OCAMLFLAGS)" \
+				OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
+dncl:	debug-native-code-library
+
+# generates byte-code for profiling
+profiling-byte-code:		$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \
+				REAL_RESULT="$(BCRESULT)" PROFILING="y" \
+				make_deps=yes
+pbc:	profiling-byte-code
+
+# generates native-code
+
+profiling-native-code:		$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \
+				REAL_RESULT="$(NCRESULT)" \
+				REAL_OCAMLC="$(OCAMLOPT)" \
+				PROFILING="y" \
+				make_deps=yes
+pnc:	profiling-native-code
+
+# generates byte-code libraries
+profiling-byte-code-library:	$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+				$(RES_CLIB) $(BCRESULT).cma \
+				REAL_RESULT="$(BCRESULT)" PROFILING="y" \
+				CREATE_LIB=yes \
+				make_deps=yes
+pbcl:	profiling-byte-code-library
+
+# generates native-code libraries
+profiling-native-code-library:	$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+				$(RES_CLIB) $(NCRESULT).cmxa \
+				REAL_RESULT="$(NCRESULT)" PROFILING="y" \
+				REAL_OCAMLC="$(OCAMLOPT)" \
+				CREATE_LIB=yes \
+				make_deps=yes
+pncl:	profiling-native-code-library
+
+# packs byte-code objects
+pack-byte-code:			$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT).cmo \
+				REAL_RESULT="$(BCRESULT)" \
+				PACK_LIB=yes make_deps=yes
+pabc:	pack-byte-code
+
+# packs native-code objects
+pack-native-code:		$(PRE_TARGETS)
+			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+				$(NCRESULT).cmx $(NCRESULT).$(EXT_OBJ) \
+				REAL_RESULT="$(NCRESULT)" \
+				REAL_OCAMLC="$(OCAMLOPT)" \
+				PACK_LIB=yes make_deps=yes
+panc:	pack-native-code
+
+# generates HTML-documentation
+htdoc:	$(DOC_DIR)/$(RESULT)/html/index.html
+
+# generates Latex-documentation
+ladoc:	$(DOC_DIR)/$(RESULT)/latex/doc.tex
+
+# generates PostScript-documentation
+psdoc:	$(DOC_DIR)/$(RESULT)/latex/doc.ps
+
+# generates PDF-documentation
+pdfdoc:	$(DOC_DIR)/$(RESULT)/latex/doc.pdf
+
+# generates all supported forms of documentation
+doc: htdoc ladoc psdoc pdfdoc
+
+###########################################################################
+# LOW LEVEL RULES
+
+$(REAL_RESULT):		$(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(RESULTDEPS)
+			$(REAL_OCAMLFIND) $(REAL_OCAMLC) \
+				$(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \
+				$(OBJS_LIBS) $(ALL_LDFLAGS) -o $@$(EXE) \
+				$(REAL_IMPL)
+
+nolink:			$(REAL_IMPL_INTF) $(OBJ_LINK)
+
+ifdef WIN32
+$(REAL_RESULT).dll:	$(REAL_IMPL_INTF) $(OBJ_LINK)
+			$(CAMLIDLDLL) $(CAMLIDLDLLFLAGS) $(OBJ_LINK) $(CLIBS) \
+				-o $@ $(REAL_IMPL)
+endif
+
+%$(TOPSUFFIX):		$(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS)
+			$(REAL_OCAMLFIND) $(OCAMLMKTOP) \
+				$(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \
+				$(OBJS_LIBS) $(ALL_LDFLAGS) -o $@$(EXE) \
+				$(REAL_IMPL)
+
+.SUFFIXES:		.mli .ml .cmi .cmo .cmx .cma .cmxa .$(EXT_OBJ) \
+                        .mly .di .d .$(EXT_LIB) .idl %.oxridl .c .m .$(EXT_CXX) .h .so \
+                        .rep .zog .glade
+
+ifndef STATIC
+ifdef MINGW
+# From OCaml 3.11.0, ocamlmklib is available on windows
+OCAMLMLIB_EXISTS = $(shell which $(OCAMLMKLIB))
+ifeq ($(strip $(OCAMLMLIB_EXISTS)),)
+$(DLLSONAME):		$(OBJ_LINK)
+			$(CC) $(CFLAGS) $(CFLAGS_WIN32) $(OBJ_LINK) -shared -o $@ \
+			$(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/lib%.a))) \
+			 '$(OCAMLLIBPATH)/ocamlrun.a' \
+			-Wl,--whole-archive \
+			-Wl,--export-all-symbols \
+			-Wl,--allow-multiple-definition \
+			-Wl,--enable-auto-import
+else
+$(DLLSONAME):		$(OBJ_LINK)
+			$(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \
+				-o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) \
+				$(CFRAMEWORKS:%=-framework %) \
+				$(OCAMLMKLIB_FLAGS)
+endif
+else
+ifdef MSVC
+$(DLLSONAME):		$(OBJ_LINK)
+			link /NOLOGO /DLL /OUT:$@ $(OBJ_LINK) \
+			 $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/%.lib))) \
+			 '$(OCAMLLIBPATH)/ocamlrun.lib'
+
+else
+$(DLLSONAME):		$(OBJ_LINK)
+			$(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \
+				-o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) $(CFRAMEWORKS:%=-framework %) \
+				$(OCAMLMKLIB_FLAGS)
+endif
+endif
+endif
+
+ifndef LIB_PACK_NAME
+$(RESULT).cma:		$(REAL_IMPL_INTF) $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS)
+			$(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@ $(REAL_IMPL)
+
+$(RESULT).cmxa $(RESULT).$(EXT_LIB):	$(REAL_IMPL_INTF) $(EXTRADEPS) $(RESULTDEPS)
+			$(REAL_OCAMLFIND) $(OCAMLOPT) -a $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@ $(REAL_IMPL)
+else
+# Packing a bytecode library
+LIB_PACK_NAME_MLI = $(wildcard $(LIB_PACK_NAME).mli)
+ifeq ($(LIB_PACK_NAME_MLI),)
+LIB_PACK_NAME_CMI = $(LIB_PACK_NAME).cmi
+else
+# $(LIB_PACK_NAME).mli exists, it likely depends on other compiled interfaces
+LIB_PACK_NAME_CMI =
+$(LIB_PACK_NAME).cmi: $(REAL_IMPL_INTF)
+endif
+ifdef BYTE_OCAML
+$(LIB_PACK_NAME_CMI) $(LIB_PACK_NAME).cmo: $(REAL_IMPL_INTF)
+			$(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack -o $(LIB_PACK_NAME).cmo $(OCAMLLDFLAGS) $(REAL_IMPL)
+# Packing into a unit which can be transformed into a library
+# Remember the .ml's must have been compiled with -for-pack $(LIB_PACK_NAME)
+else
+$(LIB_PACK_NAME_CMI) $(LIB_PACK_NAME).cmx: $(REAL_IMPL_INTF)
+			$(REAL_OCAMLFIND) $(OCAMLOPT) -pack -o $(LIB_PACK_NAME).cmx  $(OCAMLLDFLAGS) $(REAL_IMPL)
+endif
+
+$(RESULT).cma:		$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS)
+			$(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@ $(LIB_PACK_NAME).cmo
+
+$(RESULT).cmxa $(RESULT).$(EXT_LIB):	$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx $(EXTRADEPS) $(RESULTDEPS)
+			$(REAL_OCAMLFIND) $(OCAMLOPT) -a $(OBJS_LIBS) $(filter-out -custom, $(ALL_LDFLAGS)) -o $@ $(LIB_PACK_NAME).cmx
+endif
+
+$(RES_CLIB): 		$(OBJ_LINK)
+ifndef MSVC
+  ifneq ($(strip $(OBJ_LINK)),)
+		      $(AR) rcs $@ $(OBJ_LINK)
+  endif
+else
+  ifneq ($(strip $(OBJ_LINK)),)
+			lib -nologo -debugtype:cv -out:$(RES_CLIB) $(OBJ_LINK)
+  endif
+endif
+
+%.cmi:	%.mli $(EXTRADEPS)
+			$(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
+			if [ -z "$$pp" ]; then \
+			  $(ECHO) $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
+				-c $(THREAD_FLAG) $(ANNOT_FLAG) \
+				$(OCAMLFLAGS) $(INCFLAGS) $<; \
+			  $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
+				-c $(THREAD_FLAG) $(ANNOT_FLAG) \
+				$(OCAMLFLAGS) $(INCFLAGS) $<; \
+			else \
+			    $(ECHO) $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
+				-c -pp \"$$pp $(PPFLAGS)\" $(THREAD_FLAG) $(ANNOT_FLAG) \
+				$(OCAMLFLAGS) $(INCFLAGS) $<; \
+			    $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
+				-c -pp "$$pp $(PPFLAGS)" $(THREAD_FLAG) $(ANNOT_FLAG) \
+				$(OCAMLFLAGS) $(INCFLAGS) $<; \
+			fi
+
+%.cmi: %$(IMPL_SUF);
+
+%$(IMPL_SUF) %.$(EXT_OBJ):	%.ml $(EXTRADEPS)
+			$(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
+			if [ -z "$$pp" ]; then \
+			  $(ECHO) $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
+				-c $(ALL_OCAMLCFLAGS) $<; \
+			  $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
+				-c $(ALL_OCAMLCFLAGS) $<; \
+			else \
+			  $(ECHO) $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
+				-c -pp \"$$pp $(PPFLAGS)\" $(ALL_OCAMLCFLAGS) $<; \
+			  $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
+				-c -pp "$$pp $(PPFLAGS)" $(ALL_OCAMLCFLAGS) $<; \
+			fi
+
+.PRECIOUS:		%.ml
+%.ml:			%.mll
+			$(OCAMLLEX) $(LFLAGS) $<
+
+.PRECIOUS:              %.ml %.mli
+%.ml %.mli:             %.mly
+			$(OCAMLYACC) $(YFLAGS) $<
+			$(QUIET)pp=`sed -n -e 's/.*(\*pp \([^*]*\) \*).*/\1/p;q' $<`; \
+			if [ ! -z "$$pp" ]; then \
+			  mv $*.ml $*.ml.temporary; \
+			  echo "(*pp $$pp $(PPFLAGS)*)" > $*.ml; \
+			  cat $*.ml.temporary >> $*.ml; \
+			  rm $*.ml.temporary; \
+			  mv $*.mli $*.mli.temporary; \
+			  echo "(*pp $$pp $(PPFLAGS)*)" > $*.mli; \
+			  cat $*.mli.temporary >> $*.mli; \
+			  rm $*.mli.temporary; \
+			fi
+
+
+.PRECIOUS:		%.ml
+%.ml:			%.rep
+			$(CAMELEON_REPORT) $(CAMELEON_REPORT_FLAGS) -gen $<
+
+.PRECIOUS:		%.ml
+%.ml:			%.zog
+			$(CAMELEON_ZOGGY)  $(CAMELEON_ZOGGY_FLAGS) -impl $< > $@
+
+.PRECIOUS:		%.ml
+%.ml:			%.glade
+			$(OCAML_GLADECC)  $(OCAML_GLADECC_FLAGS) $< > $@
+
+.PRECIOUS:		%.ml %.mli
+%.ml %.mli:		%.oxridl
+			$(OXRIDL) $<
+
+.PRECIOUS:		%.ml %.mli %_stubs.c %.h
+%.ml %.mli %_stubs.c %.h:		%.idl
+			$(CAMLIDL) $(MAYBE_IDL_HEADER) $(IDLFLAGS) \
+				$(CAMLIDLFLAGS) $<
+			$(QUIET)if [ $(NOIDLHEADER) ]; then touch $*.h; fi
+
+%.$(EXT_OBJ):	%.c
+			$(OCAMLC) -c -cc "$(CC)" -ccopt "$(CFLAGS) \
+				$(CPPFLAGS) $(CPPFLAGS_WIN32) \
+				$(CFLAGS_WIN32) $(CINCFLAGS) $(CFLAG_O)$@ " $<
+
+%.$(EXT_OBJ):	%.m
+			$(CC) -c $(CFLAGS) $(CINCFLAGS) $(CPPFLAGS) \
+				-I'$(OCAMLLIBPATH)' \
+				$< $(CFLAG_O)$@
+
+%.$(EXT_OBJ): %.$(EXT_CXX)
+			$(CXX) -c $(CXXFLAGS) $(CINCFLAGS) $(CPPFLAGS) \
+				-I'$(OCAMLLIBPATH)' \
+				$< $(CFLAG_O)$@
+
+$(MLDEPDIR)/%.d:	%.ml
+			$(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi
+			$(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
+			if [ -z "$$pp" ]; then \
+			  $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \
+				$(INCFLAGS) $< \> $@; \
+			  $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \
+				$(INCFLAGS) $< > $@; \
+			else \
+			  $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \
+				-pp \"$$pp $(PPFLAGS)\" $(INCFLAGS) $< \> $@; \
+			  $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \
+				-pp "$$pp $(PPFLAGS)" $(INCFLAGS) $< > $@; \
+			fi
+
+$(BCDIDIR)/%.di $(NCDIDIR)/%.di:	%.mli
+			$(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi
+			$(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
+			if [ -z "$$pp" ]; then \
+			  $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(INCFLAGS) $< \> $@; \
+			  $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(INCFLAGS) $< > $@; \
+			else \
+			  $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \
+			    -pp \"$$pp $(PPFLAGS)\" $(INCFLAGS) $< \> $@; \
+			  $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \
+			    -pp "$$pp $(PPFLAGS)" $(INCFLAGS) $< > $@; \
+			fi
+
+$(DOC_DIR)/$(RESULT)/html:
+	mkdir -p $@
+
+$(DOC_DIR)/$(RESULT)/html/index.html: $(DOC_DIR)/$(RESULT)/html $(DOC_FILES)
+	rm -rf $</*
+	$(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $(FIRST_DOC_FILE)`; \
+	if [ -z "$$pp" ]; then \
+	  $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDOC) $(OCAML_FIND_PACKAGES) -html -d $< $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES); \
+	  $(REAL_OCAMLFIND) $(OCAMLDOC) $(OCAML_FIND_PACKAGES) -html -d $< $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES); \
+	else \
+	  $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDOC) $(OCAML_FIND_PACKAGES) -pp \"$$pp $(PPFLAGS)\" -html -d $< $(OCAMLDOCFLAGS) \
+	  	$(INCFLAGS) $(DOC_FILES); \
+	  $(REAL_OCAMLFIND) $(OCAMLDOC) $(OCAML_FIND_PACKAGES) -pp "$$pp $(PPFLAGS)" -html -d $< $(OCAMLDOCFLAGS) \
+	  	$(INCFLAGS) $(DOC_FILES); \
+	fi
+
+$(DOC_DIR)/$(RESULT)/latex:
+	mkdir -p $@
+
+$(DOC_DIR)/$(RESULT)/latex/doc.tex: $(DOC_DIR)/$(RESULT)/latex $(DOC_FILES)
+	rm -rf $</*
+	$(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $(FIRST_DOC_FILE)`; \
+	if [ -z "$$pp" ]; then \
+	  $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDOC) $(OCAML_FIND_PACKAGES) -latex $(OCAMLDOCFLAGS) $(INCFLAGS) \
+	  	$(DOC_FILES) -o $@; \
+	  $(REAL_OCAMLFIND) $(OCAMLDOC) $(OCAML_FIND_PACKAGES) -latex $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES) \
+	  	-o $@; \
+	else \
+	  $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDOC) $(OCAML_FIND_PACKAGES) -pp \"$$pp $(PPFLAGS)\" -latex $(OCAMLDOCFLAGS) \
+	  	$(INCFLAGS) $(DOC_FILES) -o $@; \
+	  $(REAL_OCAMLFIND) $(OCAMLDOC) $(OCAML_FIND_PACKAGES) -pp "$$pp $(PPFLAGS)" -latex $(OCAMLDOCFLAGS) \
+	  	$(INCFLAGS) $(DOC_FILES) -o $@; \
+	fi
+
+$(DOC_DIR)/$(RESULT)/latex/doc.ps: $(DOC_DIR)/$(RESULT)/latex/doc.tex
+	cd $(DOC_DIR)/$(RESULT)/latex && \
+	  $(LATEX) doc.tex && \
+	  $(LATEX) doc.tex && \
+	  $(DVIPS) $(DVIPSFLAGS) doc.dvi -o $(@F)
+
+$(DOC_DIR)/$(RESULT)/latex/doc.pdf: $(DOC_DIR)/$(RESULT)/latex/doc.ps
+	cd $(DOC_DIR)/$(RESULT)/latex && $(PS2PDF) $(<F)
+
+define make_subproj
+.PHONY:
+subproj_$(1):
+	$$(eval $$(call PROJ_$(1)))
+	$(QUIET)if [ "$(SUBTARGET)" != "all" ]; then \
+	  $(MAKE) -f $(OCAMLMAKEFILE) $(SUBTARGET); \
+	fi
+endef
+
+$(foreach subproj,$(SUBPROJS),$(eval $(call make_subproj,$(subproj))))
+
+.PHONY:
+subprojs: $(SUBPROJS:%=subproj_%)
+
+###########################################################################
+# (UN)INSTALL RULES FOR LIBRARIES
+
+.PHONY: libinstall
+libinstall:	all
+	$(QUIET)printf "\nInstalling library with ocamlfind\n"
+	$(OCAMLFIND) install $(OCAMLFIND_INSTFLAGS) $(RESULT) META $(LIBINSTALL_FILES)
+	$(QUIET)printf "\nInstallation successful.\n"
+
+.PHONY: libinstall-byte-code
+libinstall-byte-code:	all
+	$(QUIET)printf "\nInstalling byte-code library with ocamlfind\n"
+	$(OCAMLFIND) install $(OCAMLFIND_INSTFLAGS) $(RESULT) META \
+	  $(filter-out $(RESULT).$(EXT_LIB) $(RESULT).cmxa, $(LIBINSTALL_FILES))
+	$(QUIET)printf "\nInstallation successful.\n"
+
+.PHONY: libinstall-native-code
+libinstall-native-code:	all
+	$(QUIET)printf "\nInstalling native-code library with ocamlfind\n"
+	$(OCAMLFIND) install $(OCAMLFIND_INSTFLAGS) $(RESULT) META \
+	  $(filter-out $(DLLSONAME) $(RESULT).cma, $(LIBINSTALL_FILES))
+	$(QUIET)printf "\nInstallation successful.\n"
+
+.PHONY: libuninstall
+libuninstall:
+	$(QUIET)printf "\nUninstalling library with ocamlfind\n"
+	$(OCAMLFIND) remove $(OCAMLFIND_INSTFLAGS) $(RESULT)
+	$(QUIET)printf "\nUninstallation successful.\n"
+
+.PHONY: rawinstall
+rawinstall:	all
+	$(QUIET)printf "\nInstalling library to: $(OCAML_LIB_INSTALL)\n"
+	-install -d $(OCAML_LIB_INSTALL)
+	for i in $(LIBINSTALL_FILES); do \
+	  if [ -f $$i ]; then \
+	    install -c -m 0644 $$i $(OCAML_LIB_INSTALL); \
+	  fi; \
+	done
+	$(QUIET)printf "\nInstallation successful.\n"
+
+.PHONY: rawuninstall
+rawuninstall:
+	$(QUIET)printf "\nUninstalling library from: $(OCAML_LIB_INSTALL)\n"
+	cd $(OCAML_LIB_INSTALL) && rm $(notdir $(LIBINSTALL_FILES))
+	$(QUIET)printf "\nUninstallation successful.\n"
+
+###########################################################################
+# MAINTENANCE RULES
+
+.PHONY:	clean
+clean::
+	rm -f $(TARGETS) $(TRASH)
+	rm -rf $(BCDIDIR) $(NCDIDIR) $(MLDEPDIR)
+
+.PHONY:	cleanup
+cleanup::
+	rm -f $(NONEXECS) $(TRASH)
+	rm -rf $(BCDIDIR) $(NCDIDIR) $(MLDEPDIR)
+
+.PHONY: clean-doc
+clean-doc::
+	rm -rf $(DOC_DIR)/$(RESULT)
+
+.PHONY: clean-all
+clean-all:: clean clean-doc
+
+.PHONY: nobackup
+nobackup:
+	rm -f *.bak *~ *.dup

+ 85 - 0
ast.ml

@@ -0,0 +1,85 @@
+type monop = Neg | Not
+type binop = Add | Sub | Mul | Div | Mod
+           | Eq | Ne | Lt | Le | Gt | Ge
+           | And | Or
+type ctype = Void | Bool | Int | Float
+           | ArrayDec of ctype * string list
+           | ArrayDef of ctype * node list
+and node =
+    (* Global *)
+    | Program of node list
+    | Param of ctype * string
+    | FunDec of ctype * string * node list
+    | FunDef of bool * ctype * string * node list * node list
+    | GlobalDec of ctype * string
+    | GlobalDef of bool * ctype * string * node option
+
+    (* Statements *)
+    | VarDec of ctype * string * node option
+    | Assign of string * node
+    | Return of node
+    | If of node * node list
+    | IfElse of node * node list * node list
+    | While of node * node list
+    | DoWhile of node * node list
+    | For of string * node * node * node * node list
+    | Expr of node
+
+    (* Expressions *)
+    | BoolConst of bool
+    | IntConst of int
+    | FloatConst of float
+    | ArrayConst of node list
+    | Var of string
+    | Deref of string * node list
+    | Monop of monop * node
+    | Binop of binop * node * node
+    | Cond of node * node * node
+    | TypeCast of ctype * node
+    | FunCall of string * node list
+
+(* Intermediate representations between phases *)
+type repr =
+    | Inputfile of string option * int  (* filename, verbose *)
+    | Node of node * int                (* ast, verbose *)
+    | Assembly of string list * int     (* instructions *)
+
+exception CompileError of string
+
+
+(*
+ * Template for node matching follows below.
+ *
+ * let rec visit = function
+ *     | Program (decls) ->
+ *     | Param (ctype, name) ->
+ *     | FunDec (ret_type, name, params) ->
+ *     | FunDef (export, ret_type, name, params, body) ->
+ *     | GlobalDec (ctype, name) ->
+ *     | GlobalDef (export, ctype, name, None) ->
+ *     | GlobalDef (export, ctype, name, Some init) ->
+ *
+ *     | VarDec (ctype, name, None) ->
+ *     | VarDec (ctype, name, Some init) ->
+ *     | Assign (name, value) ->
+ *     | Return (value) ->
+ *     | If (cond, body) ->
+ *     | IfElse (cond, true_body, false_body) ->
+ *     | While (cond, body) ->
+ *     | DoWhile (cond, body) ->
+ *     | For (counter, start, stop, step, body) ->
+ *     | Expr (value) ->
+ *
+ *     | BoolConst (value) ->
+ *     | IntConst (value) ->
+ *     | FloatConst (value) ->
+ *     | Var (name) ->
+ *     | Monop (op, value) ->
+ *     | Binop (op, left, right) ->
+ *     | Cond (cond, true_expr, false_expr) ->
+ *     | TypeCast (ctype, value) ->
+ *     | FunCall (name, args) ->
+ *
+ *     | node -> transform visit node
+ *
+ *)

BIN
bin32/civas


BIN
bin32/civcc


BIN
bin32/civvm


BIN
doc/milestones.pdf


BIN
doc/project.pdf


+ 88 - 0
lexer.mll

@@ -0,0 +1,88 @@
+{
+open Lexing
+open Parser
+
+exception SyntaxError of string
+
+let next_line lexbuf =
+    let pos = lexbuf.lex_curr_p in
+    lexbuf.lex_curr_p <- {
+        pos with pos_bol = lexbuf.lex_curr_pos;
+                 pos_lnum = pos.pos_lnum + 1
+    }
+
+let linenum = ref 0
+let filename = ref ""
+}
+
+rule token = parse
+    | '#'' '+['0'-'9']+' '+'"'[^'"']+'"'(' '+['1'-'4'])*'\n' as marker {
+        (*
+         * The C preprocessor inserts so called ``line markers'' into the output.
+         * These markers have the following form:
+         *
+         *  # <linenum> <filename> <flags>
+         *
+         * This marker indicates that all lines after this marker up to the next
+         * marker come from the file <filename> starting at line <linenum>. After
+         * the file name can be zero or more flags, these flags are 1, 2, 3, 4.
+         * These flags can be ignored.
+         *)
+        Scanf.sscanf marker "# %d \"%s\"" (fun i s -> linenum := i - 1;
+                                                      filename := String.copy s);
+        token lexbuf
+    }
+
+    (*| ['('')''['']''{''}'';'','] as literal { literal }*)
+
+    | '('       { LPAREN }
+    | ')'       { RPAREN }
+    | '['       { LBRACK }
+    | ']'       { RBRACK }
+    | '{'       { LBRACE }
+    | '}'       { RBRACE }
+    | ';'       { SEMICOL }
+    | ','       { COMMA }
+
+    | '='       { ASSIGN }
+    | '!'       { NOT }
+    | '+'       { ADD }
+    | '-'       { SUB }
+    | '*'       { MUL }
+    | '/'       { DIV }
+    | '%'       { MOD }
+
+    | "<="      { LE }
+    | "<"       { LT }
+    | ">="      { GE }
+    | ">"       { GT }
+    | "=="      { EQ }
+    | "!="      { NE }
+    | "&&"      { AND }
+    | "||"      { OR }
+
+    | "if"      { IF }
+    | "else"    { ELSE }
+    | "do"      { DO }
+    | "while"   { WHILE }
+    | "for"     { FOR }
+    | "return"  { RETURN }
+    | "extern"  { EXTERN }
+    | "export"  { EXPORT }
+    | "int"     { INT }
+    | "bool"    { BOOL }
+    | "float"   { FLOAT }
+    | "void"    { VOID }
+
+    | "true"    { BOOL_CONST true }
+    | "false"   { BOOL_CONST false }
+    | ['0'-'9']+ as i              { INT_CONST (int_of_string i) }
+    | ['0'-'9']+'.'['0'-'9']+ as f { FLOAT_CONST (float_of_string f) }
+    | ['A'-'Z''a'-'z']['A'-'Z''a'-'z''0'-'9''_']* as id { ID id }
+
+    | '\r'|'\n'|"\r\n"    { next_line lexbuf; token lexbuf }
+    | [' ''\t']+          { token lexbuf }
+    | "//"_* | "/*"_*"*/" { token lexbuf }
+
+    | eof       { EOF }
+    | _ as chr  { raise (SyntaxError ("Unexpected char: " ^ Char.escaped chr)) }

+ 41 - 0
main.ml

@@ -0,0 +1,41 @@
+open Ast
+
+(* Compile infile to assembly code
+ * in_channel -> int -> repr *)
+let compile infile verbose =
+    let rec run_phases ir = function
+        | [] -> ir
+        | h::t -> run_phases (h ir) t
+    in
+    run_phases (Inputfile (infile, verbose)) [
+        Parse.phase;
+        Desug.phase;
+        Print.phase;
+        (*Typecheck.phase;*)
+        (*Extern_vars.phase;*)
+        (*Dim_reduce.phase;*)
+        (*Bool_op.phase;*)
+        (*Assemble.phase;*)
+        (*Peephole.phase;*)
+        (*Print.phase;*)
+    ]
+
+(* Main function, returns exit status
+ * () -> int *)
+let main () =
+    let filename = ref None in
+    let verbose = ref 1 in
+    let args = [
+        ("-v", Arg.Int (fun i -> verbose := i), "Set verbosity")
+    ] in
+    let usage = "Usage: " ^ Sys.argv.(0) ^ " [ -v VERBOSITY ] FILE" in
+
+    try
+        Arg.parse args (fun s -> filename := Some s) usage;
+        let _ = compile !filename !verbose in
+        0
+    with CompileError msg ->
+        prerr_endline ("Error: " ^ msg);
+        -1
+
+let _ = exit (main ())

+ 149 - 0
parser.mly

@@ -0,0 +1,149 @@
+%{
+open Ast
+%}
+
+/* Tokens */
+
+%token LPAREN RPAREN LBRACK RBRACK LBRACE RBRACE SEMICOL COMMA
+%token NOT ADD SUB MUL DIV MOD
+%token EQ NE LT LE GT GE
+%token AND OR
+%token ASSIGN IF ELSE WHILE DO FOR RETURN EXTERN EXPORT
+%token INT BOOL FLOAT VOID
+%token EOF
+
+%token <bool> BOOL_CONST
+%token <float> FLOAT_CONST
+%token <int> INT_CONST
+%token <string> ID
+
+/* Types */
+
+%type <Ast.node> program decl fun_header var_dec param statement expr
+%type <Ast.node list> return_statement array_const
+%type <Ast.ctype> basic_type
+
+/* Precedence */
+
+%right ASSIGN
+%left OR
+%left AND
+%left EQ NE
+%left LT LE GT GE
+%left ADD SUB
+%left MUL DIV MOD
+%right NOT NEG CAST
+
+%nonassoc IF
+%nonassoc ELSE
+
+%start program
+
+%%
+
+basic_type : FLOAT      { Float }
+           | INT        { Int }
+           | BOOL       { Bool }
+
+program : decl*; EOF
+          { Program $1 }
+
+decl : EXTERN; fun_header; SEMICOL
+       { $2 }
+     | boption(EXPORT); fun_header; LBRACE; fun_body; RBRACE
+       { match $2 with FunDec (t, n, p) -> FunDef ($1, t, n, p, $4)
+         | _ -> raise _eRR }
+
+     | EXTERN; basic_type; ID; SEMICOL
+       { GlobalDec ($2, $3) }
+
+         | EXTERN; t=basic_type; LBRACK; d=separated_list(COMMA, ID); RBRACK; n=ID; SEMICOL
+       { GlobalDec (ArrayDec (t, d), n) }
+
+
+     | boption(EXPORT); basic_type; ID; SEMICOL
+       { GlobalDef ($1, $2, $3, None) }
+     | boption(EXPORT); basic_type; ID; ASSIGN; expr; SEMICOL
+       { GlobalDef ($1, $2, $3, Some $5) }
+
+     | e=boption(EXPORT); t=basic_type; LBRACK; d=separated_list(COMMA, expr); RBRACK; n=ID; SEMICOL
+       { GlobalDef (e, ArrayDef (t, d), n, None) }
+     | e=boption(EXPORT); t=basic_type; LBRACK; d=separated_list(COMMA, expr); RBRACK; n=ID; ASSIGN; v=expr; SEMICOL
+       { GlobalDef (e, ArrayDef (t, d), n, Some v) }
+
+fun_header : ret=basic_type; name=ID; LPAREN; params=separated_list(COMMA, param); RPAREN
+             { FunDec (ret, name, params) }
+           | VOID; name=ID; LPAREN; params=separated_list(COMMA, param); RPAREN
+             { FunDec (Void, name, params) }
+
+param : basic_type; ID  { Param ($1, $2) }
+
+fun_body : var_dec* local_fun_dec* statement* loption(return_statement)
+           { $1 @ $2 @ $3 }
+
+local_fun_dec : fun_header; LBRACE; fun_body; RBRACE
+                { match $1 with FunDec (t, n, p) -> FunDef (false, t, n, p, $3)
+                  | _ -> raise _eRR }
+
+var_dec : basic_type; ID; SEMICOL
+          { VarDec ($1, $2, None) }
+        | basic_type; ID; ASSIGN; expr; SEMICOL
+          { VarDec ($1, $2, Some $4) }
+        | t=basic_type; LBRACK; d=separated_list(COMMA, expr); RBRACK; n=ID; SEMICOL
+          { VarDec (ArrayDef (t, d), n, None) }
+        | t=basic_type; LBRACK; d=separated_list(COMMA, expr); RBRACK; n=ID; ASSIGN; v=expr; SEMICOL
+          { VarDec (ArrayDef (t, d), n, Some v) }
+
+statement : ID; ASSIGN; expr; SEMICOL
+            { Assign ($1, $3) }
+          | name=ID; LPAREN; params=separated_list(COMMA, expr); RPAREN; SEMICOL
+            { Expr (FunCall (name, params)) }
+          | IF; LPAREN; expr; RPAREN; block
+            { If ($3, $5) }                                 %prec IF
+          | IF; LPAREN; expr; RPAREN; block; ELSE; block
+            { IfElse ($3, $5, $7) }                         %prec ELSE
+          | WHILE; LPAREN; expr; RPAREN; block
+            { While ($3, $5) }
+          | DO; block; WHILE; LPAREN; expr; RPAREN; SEMICOL
+            { DoWhile ($5, $2) }
+          | FOR; LPAREN; INT; id=ID; ASSIGN; start=expr; COMMA; stop=expr; RPAREN; body=block
+            { For (id, start, stop, IntConst 1, body) }
+          | FOR; LPAREN; INT; id=ID; ASSIGN; start=expr; COMMA; stop=expr; COMMA; step=expr; RPAREN; body=block
+            { For (id, start, stop, step, body) }
+
+return_statement : RETURN; expr; SEMICOL  { [Return ($2)] }
+
+block : LBRACE; statement*; RBRACE  { $2 }
+      | statement                   { [$1] }
+
+expr : LPAREN; expr; RPAREN                 { $2 }
+     | name=ID; LPAREN; params=separated_list(COMMA, expr); RPAREN
+       { FunCall (name, params) }
+     | ID                                   { Var $1 }
+     | l=expr; op=binop; r=expr             { Binop (op, l, r) }
+     | SUB; expr                            { Monop (Neg, $2) }    %prec NEG
+     | NOT; expr                            { Monop (Not, $2) }
+     | LPAREN; basic_type; RPAREN; expr     { TypeCast ($2, $4) }  %prec CAST
+     | FLOAT_CONST                          { FloatConst $1 }
+     | INT_CONST                            { IntConst $1 }
+     | BOOL_CONST                           { BoolConst $1 }
+     | ID; array_const                      { Deref ($1, $2) }
+     | array_const                          { ArrayConst $1 }
+
+array_const : LBRACK; values=separated_list(COMMA, expr); RBRACK { values }
+
+%inline binop : ADD { Add }
+              | SUB { Sub }
+              | MUL { Mul }
+              | DIV { Div }
+              | MOD { Mod }
+              | EQ  { Eq  }
+              | NE  { Ne  }
+              | LT  { Lt  }
+              | LE  { Le  }
+              | GT  { Gt  }
+              | GE  { Ge  }
+              | AND { And }
+              | OR  { Or  }
+
+%%

+ 29 - 0
phases/desug.ml

@@ -0,0 +1,29 @@
+open Ast
+open Trav
+open Stringify
+
+let rec var_init node =
+    let move_inits body =
+        let rec trav inits = function
+            (* local declarations: collect initialisations *)
+            | VarDec (ctype, name, Some init) :: t ->
+                VarDec (ctype, name, None) :: (trav (inits @ [Assign (name, init)]) t)
+            | (VarDec (_, _, None) as h) :: t
+            | (FunDef (_, _, _, _, _) as h) :: t ->
+                 h :: (trav inits t)
+
+            (* rest of function body: recurse *)
+            | rest -> inits @ (List.map var_init rest)
+        in trav [] body
+    in
+    match node with
+    | FunDef (export, ret_type, name, params, body) ->
+        FunDef (export, ret_type, name, params, move_inits body)
+    | _ -> transform var_init node
+
+let rec phase repr =
+    let _ = print_endline "- Var init" in
+    match repr with
+        | Node (node, verbose) ->
+            Node (var_init node, verbose)
+        | _ -> failwith "invalid input for this phase"

+ 37 - 0
phases/parse.ml

@@ -0,0 +1,37 @@
+open Lexing
+open Printf
+open Ast
+
+let get_position lexbuf =
+    let pos = lexbuf.lex_curr_p in
+    sprintf "%s:%d:%d" pos.pos_fname pos.pos_lnum
+                       (pos.pos_cnum - pos.pos_bol + 1)
+
+let parse_with_error lexbuf =
+    try Some (Parser.program Lexer.token lexbuf) with
+    | Lexer.SyntaxError msg ->
+        raise (CompileError (sprintf "%s: %s" (get_position lexbuf) msg))
+    | Parser.Error ->
+        raise (CompileError (sprintf "%s: syntax error" (get_position lexbuf)))
+
+let phase repr =
+    print_endline "- Parse input";
+    match repr with
+    | Inputfile (filename, verbose) ->
+        (* TODO: run preprocessor *)
+        let infile = match filename with
+            | Some value -> open_in value
+            | None -> stdin
+        in
+        let display_name = match filename with
+            | Some value -> value
+            | None -> "stdin"
+        in
+        let lexbuf = Lexing.from_channel infile in
+        lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = display_name };
+        let ast = parse_with_error lexbuf in
+        close_in infile;
+        (match ast with
+            | None -> failwith "error during parsing"
+            | Some ast -> Node (ast, verbose))
+    | _ -> failwith "invalid input for this phase"

+ 13 - 0
phases/print.ml

@@ -0,0 +1,13 @@
+open Ast
+open Stringify
+
+let phase repr =
+    (* TODO: check verbosity *)
+    print_endline "- Print AST";
+    match repr with
+    | Node (node, verbose) ->
+        print_endline "-------------------------------------------------------";
+        print_endline (node2str node);
+        print_endline "-------------------------------------------------------";
+        repr
+    | _ -> failwith "invalid input for this phase"

+ 140 - 0
stringify.ml

@@ -0,0 +1,140 @@
+open Ast
+
+let tab = "    "
+
+(* int -> string list -> string list *)
+let indent (lines : string list) =
+    let prepend_tab line = tab ^ line in
+    List.map prepend_tab lines
+
+(* monop -> string *)
+let monop2str = function
+    | Neg -> "-"
+    | Not -> "!"
+
+(* binop -> string *)
+let binop2str = function
+    | Add -> " + "
+    | Sub -> " - "
+    | Mul -> " * "
+    | Div -> " / "
+    | Mod -> " % "
+    | Eq  -> " == "
+    | Ne  -> " != "
+    | Lt  -> " < "
+    | Le  -> " <= "
+    | Gt  -> " > "
+    | Ge  -> " >= "
+    | And -> " && "
+    | Or  -> " || "
+
+(* ctype -> string *)
+let rec type2str = function
+    | Void -> "void"
+    | Bool -> "bool"
+    | Int -> "int"
+    | Float -> "float"
+    | ArrayDec (t, dims) -> (type2str t) ^ "[" ^ (String.concat ", " dims) ^ "]"
+    | ArrayDef (t, dims) -> (type2str t) ^ "[" ^ (String.concat ", " (List.map node2str dims)) ^ "]"
+
+(* decl -> string list *)
+and node2lines node =
+    let all_str = List.map node2str in
+    let all_lines = List.map node2lines in
+    match node with
+    (* Decls *)
+    | FunDec (ret_type, name, params) ->
+        let params = String.concat ", " (all_str params) in
+        ["extern " ^ (type2str ret_type) ^ " " ^ name ^ "(" ^ params ^ ");"]
+    | FunDef (export, ret_type, name, params, body) ->
+        let export = if export then "export " else "" in
+        let params = String.concat ", " (all_str params) in
+        let header = (type2str ret_type) ^ " " ^ name ^ "(" ^ params ^ ")" in
+        let body = indent (List.concat (all_lines body)) in
+        [export ^ header ^ " {"] @
+            body @
+        ["}"]
+    | GlobalDec (var_type, name) ->
+        ["extern " ^ (type2str var_type) ^ " " ^ name ^ ";"]
+    | GlobalDef (export, ret_type, name, init) ->
+        let export = if export then "export " else "" in
+        let init = match init with
+            | Some value -> " = " ^ (node2str value)
+            | None -> ""
+        in
+        [export ^ (type2str ret_type) ^ " " ^ name ^ init ^ ";"]
+
+    (* Statements *)
+    | VarDec (var_type, name, None) ->
+        [(type2str var_type) ^ " " ^ name ^ ";"]
+    | VarDec (var_type, name, Some init) ->
+        [(type2str var_type) ^ " " ^ name ^ " = " ^ (node2str init) ^ ";"]
+    | Assign (name, value) ->
+        [name ^ " = " ^ (node2str value) ^ ";"]
+    | Expr expr ->
+        [node2str expr ^ ";"]
+    | Return value ->
+        ["return " ^ (node2str value) ^ ";"]
+    | If (cond, body) ->
+        let body = indent (List.concat (all_lines body)) in
+        ["if (" ^ (node2str cond) ^ ") {"] @
+            body @
+        ["}"]
+    | IfElse (cond, true_body, false_body) ->
+        let true_body = indent (List.concat (all_lines true_body)) in
+        let false_body = indent (List.concat (all_lines false_body)) in
+        ["if (" ^ (node2str cond) ^ ") {"] @
+            true_body @
+        ["} else {"] @
+            false_body @
+        ["}"]
+    | While (cond, body) ->
+        let body = indent (List.concat (all_lines body)) in
+        ["while (" ^ (node2str cond) ^ ") {"] @
+            body @
+        ["}"]
+    | DoWhile (cond, body) ->
+        let body = indent (List.concat (all_lines body)) in
+        ["do {"] @
+            body @
+        ["} while (" ^ (node2str cond) ^ ");"]
+    | For (counter, start, stop, step, body) ->
+        let step = match step with
+            | IntConst 1 -> ""
+            | value -> ", " ^ (node2str value)
+        in
+        let range = (node2str start) ^ ", " ^ (node2str stop) ^ step in
+        let body = indent (List.concat (all_lines body)) in
+        ["for (int " ^ counter ^ " = " ^ range ^ ") {"] @
+            body @
+        ["}"]
+
+    (* Catch-all, whould never happen *)
+    | _ -> failwith "invalid node"
+
+(* node -> string *)
+and node2str = function
+    (* Global *)
+    | Program decls ->
+        let decl2str decl = String.concat "\n" (node2lines decl) in
+        String.concat "\n\n" (List.map decl2str decls)
+    | Param (param_type, name) -> (type2str param_type) ^ " " ^ name
+
+    (* Expressions *)
+    | BoolConst b -> string_of_bool b
+    | IntConst i -> string_of_int i
+    | FloatConst f -> string_of_float f
+    | ArrayConst dims -> "[" ^ (String.concat ", " (List.map node2str dims)) ^ "]"
+    | Var v -> v
+    | Deref (name, dims) -> name ^ (node2str (ArrayConst dims))
+    | Monop (op, opnd) -> monop2str op ^ node2str opnd
+    | Binop (op, left, right) ->
+        "(" ^ node2str left ^ binop2str op ^ node2str right ^ ")"
+    | Cond (cond, t, f) ->
+        (node2str cond) ^ " ? " ^ (node2str t) ^ " : " ^ (node2str f)
+    | TypeCast (ctype, value) ->
+        "(" ^ (type2str ctype) ^ ")" ^ (node2str value)
+    | FunCall (name, args) ->
+        name ^ "(" ^ (String.concat ", " (List.map node2str args)) ^ ")"
+
+    | node -> String.concat "\n" (node2lines node)

+ 1 - 0
stringify.mli

@@ -0,0 +1 @@
+val node2str : Ast.node -> string

+ 27 - 0
test/array_init.cvc

@@ -0,0 +1,27 @@
+extern void printInt(int i);
+extern void printNewlines(int i);
+
+int[i, j] glob;
+
+export int main() {
+    int[2,3] a = [[1,2,3], [4,5,6]];
+    int[2,3] b = 7;
+
+    for(int i=0,2) {
+        for(int j=0,3) {
+            printInt(a[i,j]);
+            printNewlines(1);
+        }
+    }
+
+    printNewlines(1);
+
+    for(int i=0,2) {
+        for(int j=0,3) {
+            printInt(b[i,j]);
+            printNewlines(1);
+        }
+    }
+
+    return 0;
+}

+ 39 - 0
test/test.cvc

@@ -0,0 +1,39 @@
+extern void printInt(int i);
+
+export int glob = 0;
+
+void empty() {}
+
+void foo() {
+    int i = 0;
+
+    void bar() {
+        i = 1;
+    }
+}
+
+export int main() {
+    int i = 0;
+    int a = i + 1;
+
+    for (int j = 0, i)
+        a = a + 1;
+
+    if (a > 0) {
+        i = 1;
+
+        if (a < 5)
+            i = 2;
+    } else {
+        i = 3;
+    }
+
+    while (true)
+        printInt(i);
+
+    do
+        a = a + 1;
+    while (false);
+
+    return 0;
+}

+ 3 - 0
test/var_init.cvc

@@ -0,0 +1,3 @@
+void foo() {
+    int a = 1;
+}

+ 86 - 0
trav.ml

@@ -0,0 +1,86 @@
+include Ast
+
+(* Default tree transformation
+ * (node -> node) -> node -> node *)
+let rec transform visitor node =
+    let trav = visitor in
+    let trav_all nodes = List.map trav nodes in
+    match node with
+    | Program (decls) ->
+        Program (trav_all decls)
+    | FunDec (ret_type, name, params) ->
+        FunDec (ret_type, name, trav_all params)
+    | FunDef (export, ret_type, name, params, body) ->
+        FunDef (export, ret_type, name, trav_all params, trav_all body)
+    | GlobalDec (ctype, name) ->
+        GlobalDec (ctype, name)
+    | GlobalDef (export, ctype, name, Some init) ->
+        GlobalDef (export, ctype, name, Some (trav init))
+
+    | VarDec (ctype, name, Some init) ->
+        VarDec (ctype, name, Some (trav init))
+    | Assign (name, value) ->
+        Assign (name, trav value)
+    | Return (value) ->
+        Return (trav value)
+    | If (cond, body) ->
+        If (trav cond, trav_all body)
+    | IfElse (cond, true_body, false_body) ->
+        IfElse (trav cond, trav_all true_body, trav_all false_body)
+    | While (cond, body) ->
+        While (trav cond, trav_all body)
+    | DoWhile (cond, body) ->
+        DoWhile (trav cond, trav_all body)
+    | For (counter, start, stop, step, body) ->
+        For (counter, trav start, trav stop, trav step, trav_all body)
+    | Expr (value) ->
+        Expr (trav value)
+
+    | Monop (op, value) ->
+        Monop (op, trav value)
+    | Binop (op, left, right) ->
+        Binop (op, trav left, trav right)
+    | Cond (cond, true_expr, false_expr) ->
+        Cond (trav cond, trav true_expr, trav false_expr)
+    | TypeCast (ctype, value) ->
+        TypeCast (ctype, trav value)
+    | FunCall (name, args) ->
+        FunCall (name, trav_all args)
+
+    | _ -> node
+
+(*
+(* Visit
+ *  *)
+let rec visit visitor = function
+    let trav = visit visitor in
+    let trav_all nodes = List.map trav nodes in
+    | Program (decls) -> List.map visitor decls;
+    | Param (ctype, name) ->
+    | FunDec (ret_type, name, params) ->
+    | FunDef (export, ret_type, name, params, body) ->
+    | GlobalDec (ctype, name) ->
+    | GlobalDef (export, ctype, name, None) ->
+    | GlobalDef (export, ctype, name, Some init) ->
+
+    | VarDec (ctype, name, None) ->
+    | VarDec (ctype, name, Some init) ->
+    | Assign (name, value) ->
+    | Return (value) ->
+    | If (cond, body) ->
+    | IfElse (cond, true_body, false_body) ->
+    | While (cond, body) ->
+    | DoWhile (cond, body) ->
+    | For (counter, start, stop, step, body) ->
+    | Expr (value) ->
+
+    | BoolConst (value) ->
+    | IntConst (value) ->
+    | FloatConst (value) ->
+    | Var (name) ->
+    | Monop (op, value) ->
+    | Binop (op, left, right) ->
+    | Cond (cond, true_expr, false_expr) ->
+    | TypeCast (ctype, value) ->
+    | FunCall (name, args) ->
+*)

+ 1 - 0
trav.mli

@@ -0,0 +1 @@
+val transform : (Ast.node -> Ast.node) -> Ast.node -> Ast.node