mirror of
https://github.com/ProgramSnail/Lama.git
synced 2025-12-06 14:58:50 +00:00
External/public, better options
This commit is contained in:
parent
5a883d8fa9
commit
1a849e7a56
12 changed files with 294 additions and 93 deletions
13
doc/spec/01.general_characteristic.tex
Normal file
13
doc/spec/01.general_characteristic.tex
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
\section{General Characteristic of the Language}
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item procedural with first-class functions~--- functions can be passed as arguments, placed in data structures,
|
||||||
|
returned and constructed at runtime via closures mechanism;
|
||||||
|
\item with lexical static scoping;
|
||||||
|
\item strict~--- all arguments of function application are evaluated before function's body;
|
||||||
|
\item imperative~--- variables can be re-assigned, function calls can have side effects;
|
||||||
|
\item untyped~--- no static type checking is performed;
|
||||||
|
\item supports S-expressions and pattern-matching;
|
||||||
|
\item supports user-defined infix operators, including those defined in local scopes;
|
||||||
|
\item with automatic memory management (garbage collection).
|
||||||
|
\end{itemize}
|
||||||
50
doc/spec/02.notation.tex
Normal file
50
doc/spec/02.notation.tex
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
\section{Notation}
|
||||||
|
|
||||||
|
Pairs and tuples:
|
||||||
|
|
||||||
|
\[
|
||||||
|
\inbr{\bullet,\,\bullet,\,\dots}
|
||||||
|
\]
|
||||||
|
|
||||||
|
Lists of elements of kind $X$:
|
||||||
|
|
||||||
|
\[
|
||||||
|
X^*
|
||||||
|
\]
|
||||||
|
|
||||||
|
Deconstructing lists into sublists:
|
||||||
|
|
||||||
|
\[
|
||||||
|
h\circ t
|
||||||
|
\]
|
||||||
|
|
||||||
|
This applies also to lists of length 1. Empty list is denoted
|
||||||
|
|
||||||
|
\[
|
||||||
|
\epsilon
|
||||||
|
\]
|
||||||
|
|
||||||
|
|
||||||
|
For a mapping $f : X\to Y$ we use the following definition:
|
||||||
|
|
||||||
|
\[
|
||||||
|
f [x\gets y] = \lambda\,z\,.\,
|
||||||
|
\left\{
|
||||||
|
\begin{array}{rcl}
|
||||||
|
y &,& x = z \\
|
||||||
|
f\;x &,& x\neq z
|
||||||
|
\end{array}
|
||||||
|
\right.
|
||||||
|
\]
|
||||||
|
|
||||||
|
Empty mapping (undefined everywhere) is denoted $\Lambda$, the domain of a mapping $f$~--- $\dom{f}$, and we abbreviate
|
||||||
|
|
||||||
|
\[
|
||||||
|
\Lambda[x_1\gets y_1][x_2\gets y_2]\dots[x_k\gets y_k]
|
||||||
|
\]
|
||||||
|
|
||||||
|
as
|
||||||
|
|
||||||
|
\[
|
||||||
|
[x_1\gets y_1,\,x_2\gets y_2,\,\dots,\,x_k\gets y_k]
|
||||||
|
\]
|
||||||
20
doc/spec/03.values.tex
Normal file
20
doc/spec/03.values.tex
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
\section{Names, Values and States}
|
||||||
|
|
||||||
|
\begin{table}[t]
|
||||||
|
\begin{tabular}{cccl}
|
||||||
|
denotation & instances & definition & comments \\
|
||||||
|
\hline
|
||||||
|
$\mathscr X$ & $x,\,y,\,z,\,\dots$ & & variables \\
|
||||||
|
$\mathscr T$ & $\llang{C},\,\llang{D},\,\dots$ & & tags (constructors) \\
|
||||||
|
$\Sigma$ & $\sigma$ & $\mathscr X\to\mathscr V$ & bindings (a partial map from variables to values) \\
|
||||||
|
$\Sigma_{\mathscr X}$ & $\inbr{\sigma,\,S}$ & $2^{\mathscr X}\times\Sigma$ & local scope (a set of variable and bindings) \\
|
||||||
|
$St$ & $\inbr{\sigma_g,\,ss}$ & $\Sigma\times\Sigma^*_{\mathscr X}$ & state (global bindings and a stack of local scopes) \\
|
||||||
|
$\mathscr L$ & $l$ & & locations \\
|
||||||
|
$M$ & $\mu$ & $\mathscr L\to\mathscr C$ & abstract memory (a partial map from locations to composite values) \\
|
||||||
|
$\mathscr V$ & $v$ & $\mathbb Z\uplus \mathscr L$ & values (integer values or locations) \\
|
||||||
|
$\mathscr C$ & & $Arr\uplus Sexp \uplus Clo$ & composite values (arrays, S-expressions or closures) \\
|
||||||
|
$Arr$ & & $\mathbb N\times (\mathbb N\to\mathscr V)$ & arrays (length and element function) \\
|
||||||
|
$Sexp$ & & $\mathscr T \times Arr$ & S-expressions (tag and array of subvalues) \\
|
||||||
|
$Clo$ & & $\mathscr X \times \Sigma^*_{\mathscr X}$ & closures (function name and a stack of local scopes)
|
||||||
|
\end{tabular}
|
||||||
|
\end{table}
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
\usepackage{multirow,bigdelim}
|
\usepackage{multirow,bigdelim}
|
||||||
\usepackage{subcaption}
|
\usepackage{subcaption}
|
||||||
\usepackage{placeins}
|
\usepackage{placeins}
|
||||||
|
\usepackage{xspace}
|
||||||
|
|
||||||
\makeatletter
|
\makeatletter
|
||||||
|
|
||||||
|
|
@ -71,15 +72,12 @@
|
||||||
\renewcommand{\emptyset}{\varnothing}
|
\renewcommand{\emptyset}{\varnothing}
|
||||||
\newcommand{\dom}[1]{\mathtt{dom}\;{#1}}
|
\newcommand{\dom}[1]{\mathtt{dom}\;{#1}}
|
||||||
\newcommand{\primi}[2]{\mathbf{#1}\;{#2}}
|
\newcommand{\primi}[2]{\mathbf{#1}\;{#2}}
|
||||||
|
\newcommand{\sial}{S\textit{\lower -.5ex\hbox{I}\kern -.1667em\lower .5ex\hbox {A}}\kern -.125emL\@\xspace}
|
||||||
\definecolor{light-gray}{gray}{0.90}
|
\definecolor{light-gray}{gray}{0.90}
|
||||||
\newcommand{\graybox}[1]{\colorbox{light-gray}{#1}}
|
\newcommand{\graybox}[1]{\colorbox{light-gray}{#1}}
|
||||||
|
|
||||||
\lstdefinelanguage{ocaml}{
|
\lstdefinelanguage{sial}{
|
||||||
keywords={let, begin, end, in, match, type, and, fun,
|
keywords={fun, case, esac, do, od, if, then, else, elif, fi, skip, repeat, until, for, local},
|
||||||
function, try, mod, with, class, object, method, of, rec, repeat, until,
|
|
||||||
while, not, do, done, as, val, inherit, module, sig, @type, struct,
|
|
||||||
if, then, else, open, virtual, new, fresh, skip, od, fi, elif, for, local, return, read, write, fi, case, esac, od},
|
|
||||||
sensitive=true,
|
sensitive=true,
|
||||||
%basicstyle=\small,
|
%basicstyle=\small,
|
||||||
commentstyle=\scriptsize\rmfamily,
|
commentstyle=\scriptsize\rmfamily,
|
||||||
|
|
@ -88,7 +86,7 @@ identifierstyle=\ttfamily,
|
||||||
basewidth={0.5em,0.5em},
|
basewidth={0.5em,0.5em},
|
||||||
columns=fixed,
|
columns=fixed,
|
||||||
fontadjust=true,
|
fontadjust=true,
|
||||||
literate={->}{{$\to$}}3 {===}{{$\equiv$}}1 {=/=}{{$\not\equiv$}}1 {|>}{{$\triangleright$}}3 {\&\&\&}{{$\wedge$}}2 {|||}{{$\vee$}}2 {^}{{$\uparrow$}}1,
|
literate={->}{{$\to$}}3,
|
||||||
morecomment=[s]{(*}{*)}
|
morecomment=[s]{(*}{*)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,16 +99,12 @@ commentstyle=\scriptsize\rmfamily,
|
||||||
basewidth={0.5em,0.5em},
|
basewidth={0.5em,0.5em},
|
||||||
fontadjust=true,
|
fontadjust=true,
|
||||||
escapechar=!,
|
escapechar=!,
|
||||||
language=ocaml
|
language=sial
|
||||||
}
|
}
|
||||||
|
|
||||||
\sloppy
|
\sloppy
|
||||||
|
|
||||||
\newcommand{\ocaml}{\texttt{OCaml}\xspace}
|
\title{\sial Language Definition}
|
||||||
|
|
||||||
\theoremstyle{definition}
|
|
||||||
|
|
||||||
\title{Introduction to Programming Languages, Compilers and Tools}
|
|
||||||
|
|
||||||
\author{Dmitry Boulytchev}
|
\author{Dmitry Boulytchev}
|
||||||
|
|
||||||
|
|
@ -118,13 +112,8 @@ language=ocaml
|
||||||
|
|
||||||
\maketitle
|
\maketitle
|
||||||
|
|
||||||
\input{01}
|
\input{01.general_characteristic}
|
||||||
\input{02}
|
\input{02.notation}
|
||||||
\input{03}
|
\input{03.values}
|
||||||
\input{04}
|
|
||||||
\input{05}
|
|
||||||
\input{06}
|
|
||||||
\input{07}
|
|
||||||
\input{08}
|
|
||||||
|
|
||||||
\end{document}
|
\end{document}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
external fun printf ();
|
||||||
|
|
||||||
fun insert (tree, value) {
|
fun insert (tree, value) {
|
||||||
case tree of
|
case tree of
|
||||||
Empty -> return Node (value, Empty, Empty)
|
Empty -> return Node (value, Empty, Empty)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
external fun printf ();
|
||||||
|
|
||||||
fun collect_ints_acc (v, tail) {
|
fun collect_ints_acc (v, tail) {
|
||||||
local i;
|
local i;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
external fun printf ();
|
||||||
|
|
||||||
local lists = [
|
local lists = [
|
||||||
{},
|
{},
|
||||||
{1, 2, 3, 4},
|
{1, 2, 3, 4},
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
external fun printf ();
|
||||||
|
|
||||||
fun hd (l) {
|
fun hd (l) {
|
||||||
case l of
|
case l of
|
||||||
h : _ -> return h
|
h : _ -> return h
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ let parse infile =
|
||||||
"while"; "do"; "od";
|
"while"; "do"; "od";
|
||||||
"repeat"; "until";
|
"repeat"; "until";
|
||||||
"for";
|
"for";
|
||||||
"fun"; "local"; "return";
|
"fun"; "local"; "public"; "external"; "return";
|
||||||
"length";
|
"length";
|
||||||
"string";
|
"string";
|
||||||
"case"; "of"; "esac"; "when";
|
"case"; "of"; "esac"; "when";
|
||||||
|
|
@ -32,20 +32,75 @@ let parse infile =
|
||||||
)
|
)
|
||||||
(ostap (!(Language.parse Language.Infix.default) -EOF))
|
(ostap (!(Language.parse Language.Infix.default) -EOF))
|
||||||
|
|
||||||
|
exception Commandline_error of string
|
||||||
|
|
||||||
|
class options args =
|
||||||
|
let n = Array.length args in
|
||||||
|
let rec fix f = f (fix f) in
|
||||||
|
object (self)
|
||||||
|
val i = ref 1
|
||||||
|
val infile = ref (None : string option)
|
||||||
|
val paths = ref ([] : string list)
|
||||||
|
val mode = ref (`Default : [`Default | `Eval | `SM | `Compile ])
|
||||||
|
val help = ref false
|
||||||
|
initializer
|
||||||
|
let rec loop () =
|
||||||
|
match self#peek with
|
||||||
|
| Some opt ->
|
||||||
|
(match opt with
|
||||||
|
| "-c" -> self#set_mode `Compile
|
||||||
|
| "-I" -> (match self#peek with None -> raise (Commandline_error "path expected after '-I' specifier") | Some path -> self#add_include_path path)
|
||||||
|
| "-s" -> self#set_mode `SM
|
||||||
|
| "-i" -> self#set_mode `Eval
|
||||||
|
| "-h" -> self#set_help
|
||||||
|
| _ ->
|
||||||
|
if opt.[0] = '-'
|
||||||
|
then raise (Commandline_error (Printf.sprintf "invalid command line specifier ('%s')" opt))
|
||||||
|
else self#set_infile opt
|
||||||
|
);
|
||||||
|
loop ()
|
||||||
|
| None -> ()
|
||||||
|
in loop ()
|
||||||
|
method private set_infile name =
|
||||||
|
match !infile with
|
||||||
|
| None -> infile := Some name
|
||||||
|
| Some name' -> raise (Commandline_error (Printf.sprintf "input file ('%s') already specified" name'))
|
||||||
|
method private add_include_path path =
|
||||||
|
paths := path :: !paths
|
||||||
|
method private set_mode s =
|
||||||
|
match !mode with
|
||||||
|
| `Default -> mode := s
|
||||||
|
| _ -> raise (Commandline_error "extra compilation mode specifier")
|
||||||
|
method private peek =
|
||||||
|
let j = !i in
|
||||||
|
if j < n
|
||||||
|
then (incr i; Some (args.(j)))
|
||||||
|
else None
|
||||||
|
method private set_help = help := true
|
||||||
|
method get_mode = !mode
|
||||||
|
method get_infile =
|
||||||
|
match !infile with
|
||||||
|
| None -> raise (Commandline_error "input file not specified")
|
||||||
|
| Some name -> name
|
||||||
|
method get_help = !help
|
||||||
|
method get_include_paths = !paths
|
||||||
|
end
|
||||||
|
|
||||||
let main =
|
let main =
|
||||||
(* try*)
|
(* try*)
|
||||||
let interpret = Sys.argv.(1) = "-i" in
|
let cmd = new options Sys.argv in
|
||||||
|
|
||||||
|
(*let interpret = Sys.argv.(1) = "-i" in
|
||||||
let stack = Sys.argv.(1) = "-s" in
|
let stack = Sys.argv.(1) = "-s" in
|
||||||
let to_compile = not (interpret || stack) in
|
let to_compile = not (interpret || stack) in
|
||||||
let infile = Sys.argv.(if not to_compile then 2 else 1) in
|
let infile = Sys.argv.(if not to_compile then 2 else 1) in
|
||||||
match (try parse infile with Language.Semantic_error msg -> `Fail msg) with
|
*)
|
||||||
|
match (try parse cmd#get_infile with Language.Semantic_error msg -> `Fail msg) with
|
||||||
| `Ok prog ->
|
| `Ok prog ->
|
||||||
if to_compile
|
(match cmd#get_mode with
|
||||||
then (
|
| `Default | `Compile ->
|
||||||
let basename = Filename.chop_suffix infile ".expr" in
|
ignore @@ X86.build cmd prog
|
||||||
ignore @@ X86.build prog basename
|
| _ ->
|
||||||
)
|
|
||||||
else (
|
|
||||||
(* Printf.printf "Program:\n%s\n" (GT.show(Language.Expr.t) prog);*)
|
(* Printf.printf "Program:\n%s\n" (GT.show(Language.Expr.t) prog);*)
|
||||||
(*Format.printf "Program\n%s\n%!" (HTML.toHTML ((GT.html(Language.Expr.t)) prog));*)
|
(*Format.printf "Program\n%s\n%!" (HTML.toHTML ((GT.html(Language.Expr.t)) prog));*)
|
||||||
let rec read acc =
|
let rec read acc =
|
||||||
|
|
@ -57,7 +112,7 @@ let main =
|
||||||
in
|
in
|
||||||
let input = read [] in
|
let input = read [] in
|
||||||
let output =
|
let output =
|
||||||
if interpret
|
if cmd#get_mode = `Eval
|
||||||
then Language.eval prog input
|
then Language.eval prog input
|
||||||
else SM.run (SM.compile prog) input
|
else SM.run (SM.compile prog) input
|
||||||
in
|
in
|
||||||
|
|
|
||||||
|
|
@ -328,7 +328,7 @@ module Expr =
|
||||||
(* leave a scope *) | Leave
|
(* leave a scope *) | Leave
|
||||||
(* intrinsic (for evaluation) *) | Intrinsic of (t config, t config) arrow
|
(* intrinsic (for evaluation) *) | Intrinsic of (t config, t config) arrow
|
||||||
(* control (for control flow) *) | Control of (t config, t * t config) arrow
|
(* control (for control flow) *) | Control of (t config, t * t config) arrow
|
||||||
and decl = [`Fun of string list * t | `Variable of t option]
|
and decl = [`Local | `Public | `Extern] * [`Fun of string list * t | `Variable of t option]
|
||||||
with show,html
|
with show,html
|
||||||
|
|
||||||
(* Reff : parsed expression should return value Reff (look for ":=");
|
(* Reff : parsed expression should return value Reff (look for ":=");
|
||||||
|
|
@ -416,11 +416,16 @@ module Expr =
|
||||||
let vars, body, bnds =
|
let vars, body, bnds =
|
||||||
List.fold_left
|
List.fold_left
|
||||||
(fun (vs, bd, bnd) -> function
|
(fun (vs, bd, bnd) -> function
|
||||||
| (name, `Variable value) -> (name, true) :: vs, (match value with None -> bd | Some v -> Seq (Ignore (Assign (Ref name, v)), bd)), bnd
|
| (name, (_, `Variable value)) -> (name, true) :: vs, (match value with None -> bd | Some v -> Seq (Ignore (Assign (Ref name, v)), bd)), bnd
|
||||||
| (name, `Fun (args, b)) -> (name, false) :: vs, bd, (name, Value.FunRef (name, args, b, 1 + State.level st)) :: bnd
|
| (name, (_, `Fun (args, b))) -> (name, false) :: vs, bd, (name, Value.FunRef (name, args, b, 1 + State.level st)) :: bnd
|
||||||
)
|
)
|
||||||
([], body, [])
|
([], body, [])
|
||||||
(List.rev defs)
|
(List.rev @@
|
||||||
|
List.map (function
|
||||||
|
| (name, (`Extern, _)) -> raise (Semantic_error (Printf.sprintf "external names ('%s') not supported in evaluation" name))
|
||||||
|
| x -> x
|
||||||
|
)
|
||||||
|
defs)
|
||||||
in
|
in
|
||||||
eval (State.push st (State.from_list bnds) vars, i, o, vs) k (Seq (body, Leave))
|
eval (State.push st (State.from_list bnds) vars, i, o, vs) k (Seq (body, Leave))
|
||||||
| Unit ->
|
| Unit ->
|
||||||
|
|
@ -447,7 +452,7 @@ module Expr =
|
||||||
in
|
in
|
||||||
eval (st, i, o, v :: vs) Skip k
|
eval (st, i, o, v :: vs) Skip k
|
||||||
| Ref x ->
|
| Ref x ->
|
||||||
eval (st, i, o, (Value.Var (Value.Global x)) :: vs) Skip k
|
eval (st, i, o, (Value.Var (Value.Global x)) :: vs) Skip k (* only Value.Global is supported in interpretation *)
|
||||||
| Array xs ->
|
| Array xs ->
|
||||||
eval conf k (schedule_list (xs @ [Intrinsic (fun (st, i, o, vs) -> let es, vs' = take (List.length xs) vs in Builtin.eval (st, i, o, vs') (List.rev es) ".array")]))
|
eval conf k (schedule_list (xs @ [Intrinsic (fun (st, i, o, vs) -> let es, vs' = take (List.length xs) vs in Builtin.eval (st, i, o, vs') (List.rev es) ".array")]))
|
||||||
| Sexp (t, xs) ->
|
| Sexp (t, xs) ->
|
||||||
|
|
@ -700,8 +705,7 @@ module Expr =
|
||||||
| %"for" i:parse[def][infix][Void] "," c:parse[def][infix][Val] "," s:parse[def][infix][Void] %"do" b:scope[def][infix][Void][parse def] => {isVoid atr} => %"od"
|
| %"for" i:parse[def][infix][Void] "," c:parse[def][infix][Val] "," s:parse[def][infix][Void] %"do" b:scope[def][infix][Void][parse def] => {isVoid atr} => %"od"
|
||||||
{Seq (i, While (c, Seq (b, s)))}
|
{Seq (i, While (c, Seq (b, s)))}
|
||||||
|
|
||||||
| %"repeat" s:scope[def][infix][Void][parse def] %"until" e:basic[def][infix][Val]
|
| %"repeat" s:scope[def][infix][Void][parse def] %"until" e:basic[def][infix][Val] => {isVoid atr} => {Repeat (s, e)}
|
||||||
=> {isVoid atr} => {Repeat (s, e)}
|
|
||||||
| %"return" e:basic[def][infix][Val]? => {isVoid atr} => {Return e}
|
| %"return" e:basic[def][infix][Val]? => {isVoid atr} => {Return e}
|
||||||
|
|
||||||
| %"case" e:parse[def][infix][Val] %"of" bs:!(Util.listBy1)[ostap ("|")][ostap (!(Pattern.parse) -"->" parse[def][infix][atr])] %"esac"
|
| %"case" e:parse[def][infix][Val] %"of" bs:!(Util.listBy1)[ostap ("|")][ostap (!(Pattern.parse) -"->" parse[def][infix][atr])] %"esac"
|
||||||
|
|
@ -793,28 +797,42 @@ module Definition =
|
||||||
(* The type for a definition: aither a function/infix, or a local variable *)
|
(* The type for a definition: aither a function/infix, or a local variable *)
|
||||||
type t = string * [`Fun of string list * Expr.t | `Variable of Expr.t option]
|
type t = string * [`Fun of string list * Expr.t | `Variable of Expr.t option]
|
||||||
|
|
||||||
|
let unopt_mod = function None -> `Local | Some m -> m
|
||||||
|
|
||||||
ostap (
|
ostap (
|
||||||
arg : LIDENT;
|
arg : LIDENT;
|
||||||
position[ass][coord][newp]:
|
position[ass][coord][newp]:
|
||||||
%"at" s:STRING {Infix.at coord (unquote s) newp}
|
%"at" s:STRING {Infix.at coord (unquote s) newp}
|
||||||
| f:(%"before" {Infix.before} | %"after" {Infix.after}) s:STRING {f coord (unquote s) newp ass};
|
| f:(%"before" {Infix.before} | %"after" {Infix.after}) s:STRING {f coord (unquote s) newp ass};
|
||||||
head[infix]:
|
head[infix]:
|
||||||
%"fun" name:LIDENT {name, infix}
|
m:(%"external" {`Extern} | %"public" {`Public})? %"fun" name:LIDENT {unopt_mod m, name, name, infix}
|
||||||
| ass:(%"infix" {`Nona} | %"infixl" {`Lefta} | %"infixr" {`Righta})
|
| m:(%"public" {`Public})? ass:(%"infix" {`Nona} | %"infixl" {`Lefta} | %"infixr" {`Righta})
|
||||||
l:$ op:(s:STRING {unquote s})
|
l:$ op:(s:STRING {unquote s})
|
||||||
md:position[ass][l#coord][op] {
|
md:position[ass][l#coord][op] {
|
||||||
let name = Expr.infix_name op in
|
let name = Expr.infix_name op in
|
||||||
match md (Expr.sem name) infix with
|
match md (Expr.sem name) infix with
|
||||||
| `Ok infix' -> name, infix'
|
| `Ok infix' -> unopt_mod m, op, name, infix'
|
||||||
| `Fail msg -> raise (Semantic_error msg)
|
| `Fail msg -> raise (Semantic_error msg)
|
||||||
};
|
};
|
||||||
local_var[infix][expr][def]: name:LIDENT value:(-"=" expr[def][infix][Expr.Val])? {name, `Variable value};
|
local_var[m][infix][expr][def]: name:LIDENT value:(-"=" expr[def][infix][Expr.Val])? {
|
||||||
|
match m, value with
|
||||||
|
| `Extern, Some _ -> raise (Semantic_error (Printf.sprintf "initial value for an external variable '%s' can not be specified" name))
|
||||||
|
| _ -> name, (m,`Variable value)
|
||||||
|
};
|
||||||
parse[infix][expr][def]:
|
parse[infix][expr][def]:
|
||||||
%"local" locs:!(Util.list (local_var infix expr def)) ";" {locs, infix}
|
m:(%"local" {`Local} | %"public" {`Public} | %"external" {`Extern})
|
||||||
| <(name, infix')> : head[infix] "(" args:!(Util.list0 arg) ")"
|
locs:!(Util.list (local_var m infix expr def)) ";" {locs, infix}
|
||||||
body:expr[def][infix'][Expr.Void] {
|
| - <(m, orig_name, name, infix')> : head[infix] -"(" -args:!(Util.list0 arg) -")"
|
||||||
[(name, `Fun (args, body))], infix'
|
(body:expr[def][infix'][Expr.Void] {
|
||||||
}
|
match m with
|
||||||
|
| `Extern -> raise (Semantic_error (Printf.sprintf "body for an external function '%s' can not be specified" orig_name))
|
||||||
|
| _ -> [(name, (m, `Fun (args, body)))], infix'
|
||||||
|
} |
|
||||||
|
";" {
|
||||||
|
match m with
|
||||||
|
| `Extern -> [(name, (m, `Fun (args, Expr.Skip)))], infix'
|
||||||
|
| _ -> raise (Semantic_error (Printf.sprintf "missing body for the function/infix '%s'" orig_name))
|
||||||
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
@ -836,8 +854,13 @@ let eval expr i =
|
||||||
|
|
||||||
(* Top-level parser *)
|
(* Top-level parser *)
|
||||||
ostap (
|
ostap (
|
||||||
parse[infix]: !(Expr.scope definitions infix Expr.Void (Expr.parse definitions));
|
parse[infix]:
|
||||||
|
<(d, infix')> : definitions[infix] expr:!(Expr.parse definitions infix' Expr.Void)? {
|
||||||
|
Expr.Scope (d, match expr with None -> Expr.Skip | Some e -> e)
|
||||||
|
};
|
||||||
definitions[infix]:
|
definitions[infix]:
|
||||||
<(def, infix')> : !(Definition.parse infix Expr.basic definitions) <(defs, infix'')> : definitions[infix'] {def @ defs, infix''}
|
<(def, infix')> : !(Definition.parse infix Expr.basic definitions) <(defs, infix'')> : definitions[infix'] {
|
||||||
|
def @ defs, infix''
|
||||||
|
}
|
||||||
| empty {[], infix}
|
| empty {[], infix}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
45
src/SM.ml
45
src/SM.ml
|
|
@ -30,6 +30,8 @@ open Language
|
||||||
(* checks the tag and arity of S-expression *) | TAG of string * int
|
(* checks the tag and arity of S-expression *) | TAG of string * int
|
||||||
(* checks the tag and size of array *) | ARRAY of int
|
(* checks the tag and size of array *) | ARRAY of int
|
||||||
(* checks various patterns *) | PATT of patt
|
(* checks various patterns *) | PATT of patt
|
||||||
|
(* external definition *) | EXTERN of string
|
||||||
|
(* public definition *) | PUBLIC of string
|
||||||
with show
|
with show
|
||||||
|
|
||||||
(* The type for the stack machine program *)
|
(* The type for the stack machine program *)
|
||||||
|
|
@ -94,6 +96,7 @@ let rec eval env (((cstack, stack, glob, loc, i, o) as conf) : config) = functio
|
||||||
Printf.eprintf "end\n";
|
Printf.eprintf "end\n";
|
||||||
*)
|
*)
|
||||||
(match insn with
|
(match insn with
|
||||||
|
| PUBLIC _ | EXTERN _ -> eval env conf prg'
|
||||||
| BINOP op -> let y::x::stack' = stack in eval env (cstack, (Value.of_int @@ Expr.to_func op (Value.to_int x) (Value.to_int y)) :: stack', glob, loc, i, o) prg'
|
| BINOP op -> let y::x::stack' = stack in eval env (cstack, (Value.of_int @@ Expr.to_func op (Value.to_int x) (Value.to_int y)) :: stack', glob, loc, i, o) prg'
|
||||||
| CONST n -> eval env (cstack, (Value.of_int n)::stack, glob, loc, i, o) prg'
|
| CONST n -> eval env (cstack, (Value.of_int n)::stack, glob, loc, i, o) prg'
|
||||||
| STRING s -> eval env (cstack, (Value.of_string @@ Bytes.of_string s)::stack, glob, loc, i, o) prg'
|
| STRING s -> eval env (cstack, (Value.of_string @@ Bytes.of_string s)::stack, glob, loc, i, o) prg'
|
||||||
|
|
@ -337,12 +340,19 @@ object (self : 'self)
|
||||||
val lam_index = 0
|
val lam_index = 0
|
||||||
val scope = init_scope State.I
|
val scope = init_scope State.I
|
||||||
val fundefs = Top []
|
val fundefs = Top []
|
||||||
|
val decls = []
|
||||||
|
|
||||||
|
method global_scope = scope_index = 0
|
||||||
|
|
||||||
method get_label = (label @@ string_of_int label_index), {< label_index = label_index + 1 >}
|
method get_label = (label @@ string_of_int label_index), {< label_index = label_index + 1 >}
|
||||||
|
|
||||||
method nargs = scope.arg_index
|
method nargs = scope.arg_index
|
||||||
method nlocals = scope.nlocals
|
method nlocals = scope.nlocals
|
||||||
|
|
||||||
|
method get_decls =
|
||||||
|
List.map (function (name, `Extern) -> EXTERN name | (name, `Public) -> PUBLIC name | _ -> invalid_arg "must not happen") @@
|
||||||
|
List.filter (function (_, `Local) -> false | _ -> true) decls
|
||||||
|
|
||||||
method push_scope = {<
|
method push_scope = {<
|
||||||
scope_index = scope_index + 1;
|
scope_index = scope_index + 1;
|
||||||
scope = {
|
scope = {
|
||||||
|
|
@ -415,7 +425,14 @@ object (self : 'self)
|
||||||
}
|
}
|
||||||
>}
|
>}
|
||||||
|
|
||||||
method add_name (name : string) (mut : bool) = {<
|
method check_scope m name =
|
||||||
|
match m with
|
||||||
|
| `Local -> ()
|
||||||
|
| _ ->
|
||||||
|
raise (Semantic_error (Printf.sprintf "external/public definitions ('%s') not allowed in local scopes" name))
|
||||||
|
|
||||||
|
method add_name (name : string) (m : [`Local | `Extern | `Public]) (mut : bool) = {<
|
||||||
|
decls = (name, m) :: decls;
|
||||||
scope = {
|
scope = {
|
||||||
scope with
|
scope with
|
||||||
st = (match scope.st with
|
st = (match scope.st with
|
||||||
|
|
@ -424,6 +441,7 @@ object (self : 'self)
|
||||||
| State.G (names, s) ->
|
| State.G (names, s) ->
|
||||||
State.G (check_name_and_add names name mut, State.bind name (Value.Global name) s)
|
State.G (check_name_and_add names name mut, State.bind name (Value.Global name) s)
|
||||||
| State.L (names, s, p) ->
|
| State.L (names, s, p) ->
|
||||||
|
self#check_scope m name;
|
||||||
State.L (check_name_and_add names name mut, State.bind name (Value.Local scope.local_index) s, p)
|
State.L (check_name_and_add names name mut, State.bind name (Value.Local scope.local_index) s, p)
|
||||||
);
|
);
|
||||||
local_index = (match scope.st with State.L _ -> scope.local_index + 1 | _ -> scope.local_index);
|
local_index = (match scope.st with State.L _ -> scope.local_index + 1 | _ -> scope.local_index);
|
||||||
|
|
@ -434,7 +452,7 @@ object (self : 'self)
|
||||||
method fun_internal_name (name : string) =
|
method fun_internal_name (name : string) =
|
||||||
(match scope.st with State.G _ -> label | _ -> scope_label scope_index) name
|
(match scope.st with State.G _ -> label | _ -> scope_label scope_index) name
|
||||||
|
|
||||||
method add_fun_name (name : string) =
|
method add_fun_name (name : string) (m : [`Local | `Extern | `Public]) =
|
||||||
let name' = self#fun_internal_name name in
|
let name' = self#fun_internal_name name in
|
||||||
let st' =
|
let st' =
|
||||||
match scope.st with
|
match scope.st with
|
||||||
|
|
@ -443,9 +461,11 @@ object (self : 'self)
|
||||||
| State.G (names, s) ->
|
| State.G (names, s) ->
|
||||||
State.G (check_name_and_add names name false, State.bind name (Value.Fun name') s)
|
State.G (check_name_and_add names name false, State.bind name (Value.Fun name') s)
|
||||||
| State.L (names, s, p) ->
|
| State.L (names, s, p) ->
|
||||||
|
self#check_scope m name;
|
||||||
State.L (check_name_and_add names name false, State.bind name (Value.Fun name') s, p)
|
State.L (check_name_and_add names name false, State.bind name (Value.Fun name') s, p)
|
||||||
in
|
in
|
||||||
{<
|
{<
|
||||||
|
decls = (name, m) :: decls;
|
||||||
scope = {scope with st = st'}
|
scope = {scope with st = st'}
|
||||||
>}
|
>}
|
||||||
|
|
||||||
|
|
@ -453,8 +473,11 @@ object (self : 'self)
|
||||||
let name' = self#fun_internal_name (Printf.sprintf "lambda_%d" lam_index) in
|
let name' = self#fun_internal_name (Printf.sprintf "lambda_%d" lam_index) in
|
||||||
{< fundefs = add_fun fundefs (to_fundef name' args body scope.st); lam_index = lam_index + 1 >}, name'
|
{< fundefs = add_fun fundefs (to_fundef name' args body scope.st); lam_index = lam_index + 1 >}, name'
|
||||||
|
|
||||||
method add_fun (name : string) (args : string list) (body : Expr.t) =
|
method add_fun (name : string) (args : string list) (m : [`Local | `Extern | `Public]) (body : Expr.t) =
|
||||||
let name' = self#fun_internal_name name in
|
let name' = self#fun_internal_name name in
|
||||||
|
match m with
|
||||||
|
| `Extern -> self
|
||||||
|
| _ ->
|
||||||
{<
|
{<
|
||||||
fundefs = add_fun fundefs (to_fundef name' args body scope.st)
|
fundefs = add_fun fundefs (to_fundef name' args body scope.st)
|
||||||
>}
|
>}
|
||||||
|
|
@ -543,7 +566,7 @@ let compile p =
|
||||||
let env, code =
|
let env, code =
|
||||||
List.fold_left
|
List.fold_left
|
||||||
(fun (env, acc) (name, path) ->
|
(fun (env, acc) (name, path) ->
|
||||||
let env = env#add_name name true in
|
let env = env#add_name name `Local true in
|
||||||
let env, dsg = env#lookup name in
|
let env, dsg = env#lookup name in
|
||||||
env,
|
env,
|
||||||
([DUP] @
|
([DUP] @
|
||||||
|
|
@ -574,14 +597,14 @@ let compile p =
|
||||||
List.fold_left
|
List.fold_left
|
||||||
(fun (env, e, funs) ->
|
(fun (env, e, funs) ->
|
||||||
function
|
function
|
||||||
| name, `Fun (args, b) -> env#add_fun_name name, e, (name, args, b) :: funs
|
| name, (m, `Fun (args, b)) -> env#add_fun_name name m, e, (name, args, m, b) :: funs
|
||||||
| name, `Variable None -> env#add_name name true, e, funs
|
| name, (m, `Variable None) -> env#add_name name m true, e, funs
|
||||||
| name, `Variable (Some v) -> env#add_name name true, Expr.Seq (Expr.Ignore (Expr.Assign (Expr.Ref name, v)), e), funs
|
| name, (m, `Variable (Some v)) -> env#add_name name m true, Expr.Seq (Expr.Ignore (Expr.Assign (Expr.Ref name, v)), e), funs
|
||||||
)
|
)
|
||||||
(env, e, [])
|
(env, e, [])
|
||||||
(List.rev ds)
|
(List.rev ds)
|
||||||
in
|
in
|
||||||
let env = List.fold_left (fun env (name, args, b) -> env#add_fun name args b) env funs in
|
let env = List.fold_left (fun env (name, args, m, b) -> env#add_fun name args m b) env funs in
|
||||||
let env, flag, code = compile_expr l env e in
|
let env, flag, code = compile_expr l env e in
|
||||||
env#pop_scope, flag, code
|
env#pop_scope, flag, code
|
||||||
|
|
||||||
|
|
@ -709,6 +732,8 @@ let compile p =
|
||||||
let env = new env in
|
let env = new env in
|
||||||
let lend, env = env#get_label in
|
let lend, env = env#get_label in
|
||||||
let env, flag, code = compile_expr lend env p in
|
let env, flag, code = compile_expr lend env p in
|
||||||
let env, prg = compile_fundefs [[LABEL "main"; BEGIN ("main", 0, env#nlocals, [])] @(if flag then code @ [LABEL lend] else code) @ [END]] env in
|
let code = if flag then code @ [LABEL lend] else code in
|
||||||
let prg = List.flatten prg in
|
let has_main = List.length code > 0 in
|
||||||
|
let env, prg = compile_fundefs [if has_main then [LABEL "main"; BEGIN ("main", 0, env#nlocals, [])] @ code @ [END] else []] env in
|
||||||
|
let prg = (if has_main then [PUBLIC "main"] else []) @ env#get_decls @ List.flatten prg in
|
||||||
prg
|
prg
|
||||||
|
|
|
||||||
34
src/X86.ml
34
src/X86.ml
|
|
@ -217,6 +217,9 @@ let compile env code =
|
||||||
let stack = env#show_stack in
|
let stack = env#show_stack in
|
||||||
let env', code' =
|
let env', code' =
|
||||||
match instr with
|
match instr with
|
||||||
|
| PUBLIC name -> env#register_public name, []
|
||||||
|
| EXTERN name -> env#register_extern name, []
|
||||||
|
|
||||||
| CLOSURE name ->
|
| CLOSURE name ->
|
||||||
let pushr, popr =
|
let pushr, popr =
|
||||||
List.split @@ List.map (fun r -> (Push r, Pop r)) (env#live_registers 0)
|
List.split @@ List.map (fun r -> (Push r, Pop r)) (env#live_registers 0)
|
||||||
|
|
@ -492,6 +495,13 @@ class env prg =
|
||||||
val barrier = false (* barrier condition *)
|
val barrier = false (* barrier condition *)
|
||||||
val max_locals_size = 0
|
val max_locals_size = 0
|
||||||
val has_closure = false
|
val has_closure = false
|
||||||
|
val publics = S.empty
|
||||||
|
val externs = S.empty
|
||||||
|
|
||||||
|
method publics = S.elements publics
|
||||||
|
|
||||||
|
method register_public name = {< publics = S.add name publics >}
|
||||||
|
method register_extern name = {< externs = S.add name externs >}
|
||||||
|
|
||||||
method max_locals_size = max_locals_size
|
method max_locals_size = max_locals_size
|
||||||
|
|
||||||
|
|
@ -548,7 +558,7 @@ class env prg =
|
||||||
(* gets a name for a global variable *)
|
(* gets a name for a global variable *)
|
||||||
method loc x =
|
method loc x =
|
||||||
match x with
|
match x with
|
||||||
| Value.Global name -> M ("global_" ^ name)
|
| Value.Global name -> M ((*"global_" ^*) name)
|
||||||
| Value.Fun name -> M ("$" ^ name)
|
| Value.Fun name -> M ("$" ^ name)
|
||||||
| Value.Local i -> S i
|
| Value.Local i -> S i
|
||||||
| Value.Arg i -> S (- (i + if has_closure then 2 else 1))
|
| Value.Arg i -> S (- (i + if has_closure then 2 else 1))
|
||||||
|
|
@ -593,7 +603,7 @@ class env prg =
|
||||||
(* registers a variable in the environment *)
|
(* registers a variable in the environment *)
|
||||||
method variable x =
|
method variable x =
|
||||||
match x with
|
match x with
|
||||||
| Value.Global name -> {< globals = S.add ("global_" ^ name) globals >}
|
| Value.Global name -> {< globals = S.add ((*"global_" ^*) name) globals >}
|
||||||
| _ -> self
|
| _ -> self
|
||||||
|
|
||||||
(* registers a string constant *)
|
(* registers a string constant *)
|
||||||
|
|
@ -605,7 +615,7 @@ class env prg =
|
||||||
y, {< scount = scount + 1; stringm = m>}
|
y, {< scount = scount + 1; stringm = m>}
|
||||||
|
|
||||||
(* gets all global variables *)
|
(* gets all global variables *)
|
||||||
method globals = S.elements globals
|
method globals = S.elements (S.diff globals externs)
|
||||||
|
|
||||||
(* gets all string definitions *)
|
(* gets all string definitions *)
|
||||||
method strings = M.bindings stringm
|
method strings = M.bindings stringm
|
||||||
|
|
@ -643,24 +653,32 @@ let genasm prog =
|
||||||
let sm = SM.compile prog in
|
let sm = SM.compile prog in
|
||||||
let env, code = compile (new env sm) sm in
|
let env, code = compile (new env sm) sm in
|
||||||
let gc_start, gc_end = "__gc_data_start", "__gc_data_end" in
|
let gc_start, gc_end = "__gc_data_start", "__gc_data_end" in
|
||||||
|
let globals =
|
||||||
|
List.map (fun s -> Meta (Printf.sprintf "\t.globl\t%s" s)) ([gc_start; gc_end] @ env#publics)
|
||||||
|
in
|
||||||
let data = [Meta "\t.data";
|
let data = [Meta "\t.data";
|
||||||
Meta (Printf.sprintf "filler:\t.fill\t%d, 4, 1" env#max_locals_size);
|
Meta (Printf.sprintf "filler:\t.fill\t%d, 4, 1" env#max_locals_size);
|
||||||
Meta (Printf.sprintf "\t.globl\t%s" gc_start); Meta (Printf.sprintf "\t.globl\t%s" gc_end)] @
|
Meta (Printf.sprintf "%s:" gc_start)] @
|
||||||
[Meta (Printf.sprintf "%s:" gc_start)] @
|
(List.map (fun s -> Meta (Printf.sprintf "%s:\t.int\t1" s)) env#globals) @
|
||||||
(List.map (fun s -> Meta (Printf.sprintf "%s:\t.int\t1" s )) env#globals) @
|
|
||||||
[Meta (Printf.sprintf "%s:" gc_end)] @
|
[Meta (Printf.sprintf "%s:" gc_end)] @
|
||||||
(List.map (fun (s, v) -> Meta (Printf.sprintf "%s:\t.string\t\"%s\"" v s)) env#strings)
|
(List.map (fun (s, v) -> Meta (Printf.sprintf "%s:\t.string\t\"%s\"" v s)) env#strings)
|
||||||
in
|
in
|
||||||
let asm = Buffer.create 1024 in
|
let asm = Buffer.create 1024 in
|
||||||
List.iter
|
List.iter
|
||||||
(fun i -> Buffer.add_string asm (Printf.sprintf "%s\n" @@ show i))
|
(fun i -> Buffer.add_string asm (Printf.sprintf "%s\n" @@ show i))
|
||||||
(data @ [Meta "\t.text"; Meta "\t.globl\tmain"] @ code);
|
(globals @ data @ [Meta "\t.text"] @ code);
|
||||||
Buffer.contents asm
|
Buffer.contents asm
|
||||||
|
|
||||||
(* Builds a program: generates the assembler file and compiles it with the gcc toolchain *)
|
(* Builds a program: generates the assembler file and compiles it with the gcc toolchain *)
|
||||||
let build prog name =
|
let build cmd prog =
|
||||||
|
let name = Filename.chop_suffix cmd#get_infile ".expr" in
|
||||||
let outf = open_out (Printf.sprintf "%s.s" name) in
|
let outf = open_out (Printf.sprintf "%s.s" name) in
|
||||||
Printf.fprintf outf "%s" (genasm prog);
|
Printf.fprintf outf "%s" (genasm prog);
|
||||||
close_out outf;
|
close_out outf;
|
||||||
let inc = try Sys.getenv "RC_RUNTIME" with _ -> "../runtime" in
|
let inc = try Sys.getenv "RC_RUNTIME" with _ -> "../runtime" in
|
||||||
|
match cmd#get_mode with
|
||||||
|
| `Default ->
|
||||||
Sys.command (Printf.sprintf "gcc -g -m32 -o %s %s.s %s/runtime.a" name name inc)
|
Sys.command (Printf.sprintf "gcc -g -m32 -o %s %s.s %s/runtime.a" name name inc)
|
||||||
|
| `Compile ->
|
||||||
|
Sys.command (Printf.sprintf "gcc -g -m32 -c %s.s" name)
|
||||||
|
| _ -> invalid_arg "must not happen"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue