.ml
. The files will be organized like this: abstract syntax (syntax.ml), printing (pprint.ml), parsing (alexsynt.ml) and evaluation of instructions (eval.ml). The head of each file should contain the open statements to load the modules required for compilation.
typeop_unr
=
OPPOSE
|
NON
;;
typeop_bin
=
PLUS
|
MINUS
|
MULT
|
DIV
|
MOD
|
EQUAL
|
INF
|
INFEQ
|
SUP
|
SUPEQ
|
DIFF
|
AND
|
OR
;;
typeexpression
=
ExpInt
of
int
|
ExpVar
of
string
|
ExpStr
of
string
|
ExpUnr
of
op_unr
*
expression
|
ExpBin
of
expression
*
op_bin
*
expression
;;
typeinstruction
=
Rem
of
string
|
Goto
of
int
|
of
expression
|
Input
of
string
|
If
of
expression
*
int
|
Let
of
string
*
expression
;;
typeline
=
{
num
:
int
;
inst
:
instruction
}
;;
typeprogram
=
line
list
;;
typephrase
=
Line
of
line
|
List
|
Run
|
End
;;
letpriority_ou
=
function
NON
->
1
|
OPPOSE
->
7
letpriority_ob
=
function
MULT
|
DIV
->
6
|
PLUS
|
MINUS
->
5
|
MOD
->
4
|
EQUAL
|
INF
|
INFEQ
|
SUP
|
SUPEQ
|
DIFF
->
3
|
AND
|
OR
->
2
;;
letpp_opbin
=
function
PLUS
->
"+"
|
MULT
->
"*"
|
MOD
->
"%"
|
MINUS
->
"-"
|
DIV
->
"/"
|
EQUAL
->
" = "
|
INF
->
" < "
|
INFEQ
->
" <= "
|
SUP
->
" > "
|
SUPEQ
->
" >= "
|
DIFF
->
" <> "
|
AND
->
" & "
|
OR
->
" | "
letpp_opunr
=
function
OPPOSE
->
"-"
|
NON
->
"!"
;;
openSyntax;;
letparenthesis
x
=
"("
^
x
^
")"
;;
letpp_expression
=
let
rec
ppg
pr
=
function
ExpInt
n
->
(string_of_int
n)
|
ExpVar
v
->
v
|
ExpStr
s
->
"\""
^
s
^
"\""
|
ExpUnr
(op
,
e)->
let
res
=
(pp_opunr
op)
^
(ppg(priority_ou
op)
e)
in
if
pr
=
0
then
res
else
parenthesis
res
|
ExpBin
(e1
,
op,
e2)->
let
pr2
=
priority_ob
op
in
let
res
=
(ppg
pr2
e1)
^
(pp_opbinop)
^
(ppdpr2
e2)
(* parenthesis if the priority is not higher *)
in
if
pr2
>=
pr
then
res
else
parenthesis
res
and
ppd
pr
exp
=
match
exp
with
(* the sub-trees could only be different *)
(* in their binary operators *)
ExpBin
(e1
,
op,
e2)->
let
pr2
=
priority_ob
op
in
let
res
=
(ppg
pr2
e1)
^
(pp_opbinop)
^
(ppdpr2
e2)
in
if
pr2
>
pr
then
res
else
parenthesis
res
|
_
->
ppg
pr
exp
in
ppg
0
;;
letpp_instruction
=
function
Rem
s
->
"REM "
^
s
|
Goto
n
->
"GOTO "
^
(string_of_int
n)
|
e
->
"PRINT "
^
(pp_expression
e)
|
Input
v
->
"INPUT "
^
v
|
If
(e
,
n)
->
"IF "
^
(pp_expressione)
^
" THEN "
^
(string_of_intn)
|
Let
(v
,
e)->
"LET "
^
v
^
" = "
^
(pp_expression
e)
;;
letpp_line
l
=
(string_of_int
l
.
num)
^
" "
^
(pp_instruction
l
.
inst)
;;
openSyntax;;
typelexeme
=
Lint
of
int
|
Lident
of
string
|
Lsymbol
of
string
|
Lstring
of
string
|
Lfin
;;
typestr_lexer
=
{str
:
string;mutable
position
:
int;size
:
int}
;;
letinit_lex
s
=
{
str
=
s;position
=
0
;
size
=
String.lengths
}
;;
letadvance
cl
=
cl
.
position
<-
cl
.
position+
1
;;
letadvance_n
cl
n
=
cl
.
position
<-
cl
.
position+
n;;
letextract
pred
cl
=
let
st
=
cl
.
strand
ct
=
cl
.
positionin
let
rec
ext
n
=
if
n
<
cl.
size
&&
(pred
st
.[
n]
)then
ext
(n
+
1
)else
n
in
let
res
=
ext
ct
in
cl
.
position
<-
res
;
String.sub
cl
.
strct
(res
-
ct)
;;
letextract_int
=
let
is_integer
=
function
'0'
..
'9'
->
true
|
_
->
false
in
function
cl
->
int_of_string
(extract
is_integer
cl)
letextract_ident
=
let
is_alpha_num
=
function
'a'
..
'z'
|
'A'
..
'Z'
|
'0'
..
'9'
|
'_'
->
true
|
_
->
false
in
extract
is_alpha_num
;;
exceptionLexerError
;;
let
rec
lexer
cl
=
let
lexer_char
c
=
match
c
with
' '
|
'\t'
->
advance
cl
;
lexer
cl
|
'a'
..
'z'
|
'A'
..
'Z'
->
Lident
(extract_ident
cl)
|
'0'
..
'9'
->
Lint
(extract_int
cl)
|
'"'
->
advance
cl
;
let
res
=
Lstring
(extract
((
<>
)
'"'
)cl)
in
advance
cl
;
res
|
'+'
|
'-'
|
'*'
|
'/'
|
'%'
|
'&'
|
'|'
|
'!'
|
'='
|
'('
|
')'
->
advance
cl;
Lsymbol
(String.make
1
c)
|
'<'
|
'>'
->
advance
cl;
if
cl
.
position
>=
cl
.
sizethen
Lsymbol
(String.make
1
c)
else
let
cs
=
cl
.
str.[
cl.
position]
in
(
match
(c
,
cs)with
(
'<'
,
'='
)->
advance
cl;
Lsymbol
"<="
|
(
'>'
,
'='
)->
advance
cl;
Lsymbol
">="
|
(
'<'
,
'>'
)->
advance
cl;
Lsymbol
"<>"
|
_
->
Lsymbol
(String.make
1
c)
)
|
_
->
raise
LexerError
in
if
cl
.
position
>=
cl
.
sizethen
Lfin
else
lexer_char
cl
.
str.[
cl.
position]
;;
typeexp_elem
=
Texp
of
expression
(* expression *)
|
Tbin
of
op_bin
(* binary operator *)
|
Tunr
of
op_unr
(* unary operator *)
|
Tpg
(* right parenthesis *)
;;
exceptionParseError
;;
letsymb_unr
=
function
"!"
->
NON
|
"-"
->
OPPOSE
|
_
->
raise
ParseError
letsymb_bin
=
function
"+"
->
PLUS
|
"-"
->
MINUS
|
"*"
->
MULT
|
"/"
->
DIV
|
"%"
->
MOD
|
"="
->
EQUAL
|
"<"
->
INF
|
"<="
->
INFEQ
|
">"
->
SUP
|
">="
->
SUPEQ
|
"<>"
->
DIFF
|
"&"
->
AND
|
"|"
->
OR
|
_
->
raise
ParseError
lettsymb
s
=
try
Tbin
(symb_bin
s)
with
ParseError
->
Tunr
(symb_unr
s)
;;
letreduce
pr
=
function
(Texp
e)::(Tunr
op)::st
when
(priority_ou
op)
>=
pr
->
(Texp
(ExpUnr
(op
,
e)))::st
|
(Texp
e1)::(Tbin
op)::(Texp
e2)::st
when
(priority_ob
op)
>=
pr
->
(Texp
(ExpBin
(e2
,
op,
e1)))::st
|
_
->
raise
ParseError
;;
letrec
pile_or_reduce
lex
stack
=
match
lex
,
stack
with
Lint
n
,
_
->
(Texp
(ExpInt
n))::stack
|
Lident
v
,
_
->
(Texp
(ExpVar
v))::stack
|
Lstring
s
,
_
->
(Texp
(ExpStr
s))::stack
|
Lsymbol
"("
,
_
->
Tpg::stack
|
Lsymbol
")"
,
(Texp
e)::Tpg::st
->
(Texp
e)::st
|
Lsymbol
")"
,
_
->
pile_or_reduce
lex
(reduce
0
stack)
|
Lsymbol
s
,
_
->
let
symbole
=
if
s
<>
"-"
then
tsymb
s
(* resolve the ambiguity of the symbol ``-'' *)
(* follow the stack (i.e last exp_elem pile) *)
else
match
stack
with
(Texp
_
)::_
->
Tbin
MINUS
|
_
->
Tunr
OPPOSE
in
(
match
symbole
with
Tunr
op
->
(Tunr
op)::stack
|
Tbin
op
->
(
try
pile_or_reduce
lex
(reduce
(priority_ob
op)
stack
)
with
ParseError
->
(Tbin
op)::stack
)
|
_
->
raise
ParseError
)
|
_
,
_
->
raise
ParseError
;;
letrec
reduce_all
=
function
|
[]
->
raise
ParseError
|
[
Texpx
]
->
x
|
st
->
reduce_all
(reduce
0
st)
;;
letparse_exp
fin
cl
=
let
p
=
ref
0
in
let
rec
parse_un
stack
=
let
l
=
(
p
:=
cl.
position;
lexer
cl)
in
if
not
(fin
l)
then
parse_un
(pile_or_reduce
l
stack)
else
(
cl
.
position
<-
!
p;
reduce_all
stack
)
in
parse_un
[]
;;
letparse_inst
cl
=
match
lexer
cl
with
Lident
s
->
(
match
s
with
"REM"
->
Rem
(extract
(fun
_
->
true)
cl)
|
"GOTO"
->
Goto
(match
lexer
cl
with
Lint
p
->
p
|
_
->
raise
ParseError)
|
"INPUT"
->
Input
(match
lexer
cl
with
Lident
v
->
v
|
_
->
raise
ParseError)
|
"PRINT"
->
(parse_exp
((
=
)Lfin)
cl)
|
"LET"
->
let
l2
=
lexer
cl
and
l3
=
lexer
cl
in
(
match
l2
,
l3with
(Lident
v
,
Lsymbol
"="
)->
Let
(v
,
parse_exp((
=
)Lfin)
cl)
|
_
->
raise
ParseError
)
|
"IF"
->
let
test
=
parse_exp
((
=
)(Lident
"THEN"
))cl
in
(
match
ignore
(lexer
cl)
;
lexer
cl
with
Lint
n
->
If
(test
,
n)
|
_
->
raise
ParseError
)
|
_
->
raise
ParseError
)
|
_
->
raise
ParseError
;;
letparse
str
=
let
cl
=
init_lex
str
in
match
lexer
cl
with
Lint
n
->
Line
{
num
=
n;
inst
=
parse_instcl
}
|
Lident
"LIST"
->
List
|
Lident
"RUN"
->
Run
|
Lident
"END"
->
End
|
_
->
raise
ParseError
;;
openSyntax;;
openPprint;;
openAlexsynt;;
typevl
=
Vint
of
int
|
Vstr
of
string
|
Vbool
of
bool
;;
typeenvironment
=
(string
*
vl)
list
;;
typestate
=
{
line
:
int;
prog
:
program;
env
:
environment}
;;
exceptionRunError
of
int
letrunerr
n
=
raise
(RunError
n)
;;
letrec
eval_exp
n
envt
expr
=
match
expr
with
ExpInt
p
->
Vint
p
|
ExpVar
v
->
(
try
List.assoc
v
envt
with
Not_found
->
runerr
n
)
|
ExpUnr
(OPPOSE
,
e)->
(
match
eval_exp
n
envt
e
with
Vint
p
->
Vint
(
-
p)
|
_
->
runerr
n
)
|
ExpUnr
(NON
,
e)->
(
match
eval_exp
n
envt
e
with
Vbool
p
->
Vbool
(not
p)
|
_
->
runerr
n
)
|
ExpStr
s
->
Vstr
s
|
ExpBin
(e1
,
op,
e2)
->
match
eval_exp
n
envt
e1
,
op
,
eval_exp
n
envt
e2
with
Vint
v1
,
PLUS
,
Vint
v2
->
Vint
(v1
+
v2)
|
Vint
v1
,
MINUS
,
Vint
v2
->
Vint
(v1
-
v2)
|
Vint
v1
,
MULT
,
Vint
v2
->
Vint
(v1
*
v2)
|
Vint
v1
,
DIV
,
Vint
v2
when
v2
<>
0
->
Vint
(v1
/
v2)
|
Vint
v1
,
MOD
,
Vint
v2
when
v2
<>
0
->
Vint
(v1
mod
v2)
|
Vint
v1
,
EQUAL
,
Vint
v2
->
Vbool
(v1
=
v2)
|
Vint
v1
,
DIFF
,
Vint
v2
->
Vbool
(v1
<>
v2)
|
Vint
v1
,
INF
,
Vint
v2
->
Vbool
(v1
<
v2)
|
Vint
v1
,
SUP
,
Vint
v2
->
Vbool
(v1
>
v2)
|
Vint
v1
,
INFEQ
,
Vint
v2
->
Vbool
(v1
<=
v2)
|
Vint
v1
,
SUPEQ
,
Vint
v2
->
Vbool
(v1
>=
v2)
|
Vbool
v1
,
AND
,
Vbool
v2
->
Vbool
(v1
&&
v2)
|
Vbool
v1
,
OR
,
Vbool
v2
->
Vbool
(v1
||
v2)
|
Vstr
v1
,
PLUS
,
Vstr
v2
->
Vstr
(v1
^
v2)
|
_
,
_
,
_
->
runerr
n
;;
letrec
add
v
e
env
=
match
env
with
[]
->
[
v,
e]
|
(w
,
f)::l->
if
w
=
vthen
(v
,
e)::lelse
(w
,
f)::(addv
e
l)
;;
letrec
goto_line
n
prog
=
match
prog
with
[]
->
runerr
n
|
l::ll
->
if
l
.
num
=
n
then
prog
else
if
l
.
num<
nthen
goto_line
n
ll
else
runerr
n
;;
letprint_vl
v
=
match
v
with
Vint
n
->
print_int
n
|
Vbool
true
->
print_string
"true"
|
Vbool
false
->
print_string
"false"
|
Vstr
s
->
print_string
s
;;
leteval_inst
state
=
let
lc
,
ns
=
match
goto_line
state
.
linestate
.
progwith
[]
->
failwith
"empty program"
|
lc
::[]
->
lc
,-
1
|
lc::ls
::_
->
lc
,
ls.
num
in
match
lc
.
instwith
Rem
_
->
{
state
with
line
=
ns}
|
e
->
print_vl
(eval_exp
lc
.
numstate
.
enve)
;
print_newline
()
;
{
state
with
line
=
ns}
|
Let(v
,
e)->
let
ev
=
eval_exp
lc
.
numstate
.
enve
in
{
state
with
line
=
ns;env
=
addv
ev
state
.
env}
|
Goto
n
->
{
state
with
line
=
n}
|
Input
v
->
let
x
=
try
read_int
()
with
Failure
"int_of_string"
->
0
in
{
state
with
line
=
ns;
env
=
addv
(Vint
x)
state
.
env}
|
If
(t
,
n)->
match
eval_exp
lc
.
numstate
.
envt
with
Vbool
true
->
{
state
with
line
=
n}
|
Vbool
false
->
{
state
with
line
=
ns}
|
_
->
runerr
n
;;
letrec
run
state
=
if
state
.
line
=
-
1
then
state
else
run
(eval_inst
state)
;;
letrec
insert
line
p
=
match
p
with
[]
->
[
line]
|
l::prog
->
if
l
.
num
<
line
.
numthen
l::(insert
line
prog)
else
if
l
.
num=
line.
numthen
line::prog
else
line::l::prog
;;
letprint_prog
state
=
let
print_line
x
=
print_string
(pp_line
x)
;
print_newline
()
in
print_newline
()
;
List.iter
print_line
state
.
prog;
print_newline
()
;;
letpremiere_line
=
function
[]
->
0
|
i
::_
->
i
.
num
;;
exceptionFin
letone_command
state
=
print_string
"> "
;
flush
stdout
;
try
match
parse
(input_line
stdin)
with
Line
l
->
{
state
with
prog
=
insertl
state
.
prog}
|
List
->
(print_prog
state
;
state
)
|
Run
->
run
{state
with
line
=
premiere_line
state
.
prog}
|
End
->
raise
Fin
with
LexerError
->
print_string
"Illegal character\n"
;state
|
ParseError
->
print_string
"syntax error\n"
;state
|
RunError
n
->
print_string
"runtime error at line "
;
print_int
n
;
print_string
"\n"
;
state
;;
letgo
()
=
try
print_string
"Mini-BASIC version 0.1\n\n"
;
let
rec
loop
state
=
loop
(one_command
state)
in
loop
{
line
=
0
;prog
=[]
;env
=[]
}
withFin
->
print_string
"A bientôt...\n"
;;
$ ocamlc -c syntax.ml $ ocamlc -c pprint.ml $ ocamlc -c alexsynt.ml $ ocamlc -c eval.ml
openEval;;
go();;
$ ocamlmktop -o topbasic syntax.cmo pprint.cmo alexsynt.cmo eval.cmo mainbasic.mltest du toplevel :
$ topbasic Mini-BASIC version 0.1 > 10 PRINT "DONNER UN NOMBRE" > 20 INPUT X > 30 PRINT X > LIST 10 PRINT "DONNER UN NOMBRE" 20 INPUT X 30 PRINT X > RUN DONNER UN NOMBRE 44 44 > END A bientôt... Objective Caml version 2.04 #
$ ocamlc -custom -o basic.exe syntax.cmo pprint.cmo alexsynt.cmo eval.cmo mainbasic.mltest de l'exécutable autonome :
$ basic.exe Mini-BASIC version 0.1 > 10 PRINT "BONJOUR" > LIST 10 PRINT "BONJOUR" > RUN BONJOUR > END A bientôt... $
(***********************************************************************)
(* *)
(* Objective Caml *)
(* *)
(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
(* *)
(* Copyright 1996 Institut National de Recherche en Informatique et *)
(* Automatique. Distributed only by permission. *)
(* *)
(***********************************************************************)
(* $Id: sort.mli,v 1.1.1.1 2000/06/26 14:37:50 xleroy Exp $ *)
(* Module [Sort]: sorting and merging lists *)
vallist
:
('a
->
'a
->
bool)
->
'a
list
->
'a
list
(* Sort a list in increasing order according to an ordering predicate.
The predicate should return [true] if its first argument is
less than or equal to its second argument. *)
valarray
:
('a
->
'a
->
bool)
->
'a
array
->
unit
(* Sort an array in increasing order according to an
ordering predicate.
The predicate should return [true] if its first argument is
less than or equal to its second argument.
The array is sorted in place. *)
valmerge
:
('a
->
'a
->
bool)
->
'a
list
->
'a
list
->
'a
list
(* Merge two lists according to the given predicate.
Assuming the two argument lists are sorted according to the
predicate, [merge] returns a sorted list containing the elements
from the two lists. The behavior is undefined if the two
argument lists were not sorted. *)
(***********************************************************************)
(* *)
(* Objective Caml *)
(* *)
(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
(* *)
(* Copyright 1996 Institut National de Recherche en Informatique et *)
(* Automatique. Distributed only by permission. *)
(* *)
(***********************************************************************)
(* $Id: sort.ml,v 1.1.1.1 2000/06/26 14:37:50 xleroy Exp $ *)
(* Merging and sorting *)
openArray
letrec
merge
order
l1
l2
=
match
l1
with
[]
->
l2
|
h1
::
t1
->
match
l2
with
[]
->
l1
|
h2
::
t2
->
if
order
h1
h2
then
h1
::
merge
order
t1
l2
else
h2
::
merge
order
l1
t2
letlist
order
l
=
let
rec
initlist
=
function
[]
->
[]
|
[
e]
->
[[
e]]
|
e1::e2::rest
->
(if
order
e1
e2
then
[
e1;e2]
else
[
e2;e1]
)::
initlist
rest
in
let
rec
merge2
=
function
l1::l2::rest
->
merge
order
l1
l2
::
merge2
rest
|
x
->
x
in
let
rec
mergeall
=
function
[]
->
[]
|
[
l]
->
l
|
llist
->
mergeall
(merge2
llist)
in
mergeall(initlist
l)
letswap
arr
i
j
=
let
tmp
=
unsafe_get
arr
i
in
unsafe_set
arr
i
(unsafe_get
arr
j);
unsafe_set
arr
j
tmp
letarray
order
arr
=
let
rec
qsort
lo
hi
=
if
hi
<=
lo
then
()
else
if
hi
-
lo
<
5
then
begin
(* Use insertion sort *)
for
i
=
lo
+
1
to
hi
do
let
val_i
=
unsafe_get
arr
i
in
if
order
val_i
(unsafe_get
arr
(i
-
1
))then
begin
unsafe_set
arr
i
(unsafe_get
arr
(i
-
1
));
let
j
=
ref
(i
-
1
)in
while
!
j
>=
1
&&
order
val_i
(unsafe_get
arr
(
!
j
-
1
))do
unsafe_set
arr
!
j(unsafe_get
arr
(
!
j
-
1
));
decr
j
done;
unsafe_set
arr
!
jval_i
end
done
end
else
begin
let
mid
=
(lo
+
hi)
lsr
1
in
(* Select median value from among LO, MID, and HI *)
let
pivotpos
=
let
vlo
=
unsafe_get
arr
lo
and
vhi
=
unsafe_get
arr
hi
and
vmid
=
unsafe_get
arr
mid
in
if
order
vlo
vmid
then
if
order
vmid
vhi
then
mid
else
if
order
vlo
vhi
then
hi
else
lo
else
if
order
vhi
vmid
then
mid
else
if
order
vhi
vlo
then
hi
else
lo
in
swap
arr
pivotpos
hi;
let
pivot
=
unsafe_get
arr
hi
in
let
i
=
ref
lo
and
j
=
ref
hi
in
while
!
i
<
!
jdo
while
!
i
<
hi
&&
order
(unsafe_get
arr
!
i)pivot
do
incr
i
done;
while
!
j
>
lo
&&
order
pivot
(unsafe_get
arr
!
j)do
decr
j
done;
if
!
i
<
!
jthen
swap
arr
!
i
!
j
done;
swap
arr
!
ihi;
(* Recurse on larger half first *)
if
(
!
i
-
1
)
-
lo
>=
hi
-
(
!
i
+
1
)then
begin
qsort
lo
(
!
i
-
1
);qsort
(
!
i
+
1
)hi
end
else
begin
qsort
(
!
i
+
1
)hi;
qsort
lo
(
!
i
-
1
)
end
end
in
qsort
0
(Array.length
arr
-
1
)
letinterval
order
next
a
b
=
let
rec
aux
a
=
if
not
(order
a
b)
then
[
a]
else
a
::
aux
(next
a)
in
aux
a;;
letmain
()
=
let
il
=
Interval.interval
(
>
)(fun
x
->
x
-
1
)
5
0
0
0
0
2
0
and
il2
=
Interval.interval
(
<
)(fun
x
->
x
+
1
)
2
0
5
0
0
0
0
in
Sort.list
(
<
)il
,
Sort.list
(
>
)il2;;
main();;
ocamlc -custom -o trilbyte.exe sort.mli sort.ml interval.ml trilist.ml
ocamlopt -o trilopt.exe sort.mli sort.ml interval.ml trilist.ml
trilbyte.exe | trilopt.exe |
2,55 secondes (user) | 1,67 secondes (user) |
letmain
()
=
let
il
=
Array.of_list(Interval.interval
(
>
)(fun
x
->
x
-
1
)
5
0
0
0
0
2
0
)
and
il2
=
Array.of_list(Interval.interval
(
<
)(fun
x
->
x
+
1
)
2
0
5
0
0
0
0
)
in
Sort.array
(
<
)il
,
Sort.array
(
>
)il2;;
main();;
ocamlc -custom -o triabyte.exe sort.mli sort.ml interval.ml triarray.ml
ocamlopt -o triaoptu.exe sort.mli sort.ml interval.ml triarray.ml
triabyte.exe | triaopt.exe |
515 s | 106 s |