i ::= 0 | 1 | -1 | 2 | -2 ...
s ::= "bla" | "hallo" | ...
t ::= i Integer constant
| s String constant
| t1 + t2 Addition
| t1 - t2 Subtraction
| t.length() String length
| Integer.toString(t) Decimal notation
Parentheses are used to group subexpressions in the usual fashion.
Arith parses expressions, terminated by semicolons
";", and evaluates them step-by-step until a value is
reached.
andreas@pepper:~/Teaching/OO/arith/sml> arith
ARITH Version 0.1
Arith> -5 - 4 - 3 - 2 - 1; // a long difference
((((-5 - 4) - 3) - 2) - 1)
--> (((-9 - 3) - 2) - 1)
--> ((-12 - 2) - 1)
--> (-14 - 1)
--> -15
Arith> "hallo".length();
"hallo".length()
--> 5
Arith> Integer.toString(5 - 4).length();
Integer.toString((5 - 4)).length()
--> Integer.toString(1).length()
--> "1".length()
--> 1
Arith> Integer.toString (5 - 3 - "hallo".length() + -1).length();
Integer.toString((((5 - 3) - "hallo".length()) + -1)).length()
--> Integer.toString(((2 - "hallo".length()) + -1)).length()
--> Integer.toString(((2 - 5) + -1)).length()
--> Integer.toString((-3 + -1)).length()
--> Integer.toString(-4).length()
--> "-4".length()
--> 2
Arith> 5 - 3 + "hallo".length(Integer.toString(5));
stdin:1.17-1.44 Error:
Too many arguments to method length()
Arith> ^D andreas@pepper:~/Teaching/OO/arith/sml>
Alternatively, Arith can be invoked with some filenames as
arguments. In this case, it processes the declarations in these files in
order, aborting if some error occurs.
andreas@pepper:~/Teaching/OO/arith/sml> arith test.arith
ARITH Version 0.1
[Opening file test.arith]
((((-5 - 4) - 3) - 2) - 1)
--> (((-9 - 3) - 2) - 1)
--> ((-12 - 2) - 1)
--> (-14 - 1)
--> -15
(5 + 3)
--> 8
"hallo".length()
--> 5
Integer.toString((5 - 4)).length()
--> Integer.toString(1).length()
--> "1".length()
--> 1
-3
[Closing file test.arith]
andreas@pepper:~/Teaching/OO/arith/sml>
andreas@pepper:~/Teaching/OO/arith/sml> sml
The file arith.sml only invokes the compilation of all
files of the project arith.cm via the
compilation manager. The binary code then is written to
.heap/arith.yourArchitecture. It is
executed by running arith.
Lexer
The lexer lexer.sml transforms the input (character stream) into a stream of
tokens. Each token comes with the region it occupies in the
input.
Recognized tokens are non-negative decimal integers,
strings enclosed in double quotes, identifiers, end
of file and
( ) . ; , + - length Integer toString
The tokens with a print function are defined in
token.sml.
Parser
We have implemented a simple top-down parser. The orginal grammar
for accepted JAVA expressions (see above) is not suitable for
top-down parsing. It has to be refined to resolve ambiguities,
and parentheses have to be treated explicitly.
Refined Grammar:
Int = NUMBER
| -NUMBER
Head = STRING
| Int
| ID
| ( Exp )
Args =
| Exp, Args
Method = ID ( Args )
Summand = Head
| Summand.Method
Exp = Summand
| Exp + Summand
| Exp - Summand
Summary
Here is a summary of the Arith source files.
exp.sml Internal
represenation of Arith expressions
eval.sml Evaluation of
Arith expressions
stream.sml Streams (for
lexing, parsing...)
region.sml Input regions (=intervals)
paths.sml Region trees and
pathes in these trees
token.sml Tokens (for
lexer)
parsing.sml Error
messages for lexer and parser
lexer.sml The lexer
extsyn.sml "External
syntax", combining term and region trees
decl.sml Invokes evaluation
of parsed declarations
parser.sml Top-down
parser producing external syntax
top.sml Top-level:
command-line parsing etc.
arith.cm CM project file
arith.sml Invokes compilation
Shell script to run Arith
Download the source: arith.tgz.
Andreas Abel
Last modified: Sat Jul 13 19:53:10 CEST 2002