-- MUMBLE PARSER - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Parser
-- MUMParser.mesa of August 3, 1982 6:44 pm
-- To do: revise for viewers
DIRECTORY
Rope USING [Ref, Int];
MUMParser: DEFINITIONS =
BEGIN
-- SOURCE CHARACTERS AND LEXICAL SYMBOLS - - - - - - - - - - - - - - - - - - - - - - - -
CHAR:
TYPE =
CHARACTER;
-- The following character is expected at the end of the source string.
ETX:
CHAR = 277C;
-- A SourcePt defines a substring of the input text and gives its position in it.
SourcePt:
TYPE =
RECORD [Src: Rope.Ref, Pos: Rope.Int];
-- The lexical analyzer breaks (on demand) the input text into a sequence of Symbols, returned as a Tail.
Token: TYPE = RECORD [Sy: Symbol, SP: SourcePt];
Tail:
TYPE =
RECORD [Toks:
LIST
OF Token, Rest: SourcePt];
-- The symbols recognized by the parser. Invalid must be last.
Symbols: TYPE =
{Add, All, And, AndAlso, Array, BegExpr,
BegParms, BegRec, Blt, Box,
Cast, Cat, Center, Circle, Count,
Cut, Def, Depth, DeRef, Div, Do, Ellipse, Else,
EndExpr, EndParms, EndRec, Eql, Eqv, Erase,
For, From, GEq, Gtr, HMirror, Id, In, Is, Laminate, LEq, Lss,
Mod, NEq, Not, Num, Or, Opaque, Paste, Quote,
ReDef, Ref, Rep, RevShift, RevRot, Rot,
Sample, Shift, String, Sub, Then, ThenDo, Triangle,
VMirror, Xor, Invalid};
Ord:
PROC [Sy: Symbol]
RETURNS [
INTEGER] =
INLINE
{
RETURN [
LOOPHOLE [Sy]]};
-- Each symbol except Id, Num and String has a "standard" one-character representation, defined by the functions below. These functions return InvalidChar and Invalid, respectively, if the argument is invalid.
-- The MUMBLE editor may feel free to generate the standard character codes (e.g., by defining keyboard chords for all or some of them).
-- We'd better not to use more than 11110 symbols...
FirstSymbolChar: CHAR = 221C;
InvalidChar: CHAR = SymbolBaseChar + Ord [Invalid];
SymbolToChar: PROC [Sy: Symbol] RETURNS [Char: CHAR] = INLINE
{RETURN [IF Sy = Id OR Sy = Num OR Sy = String
THEN InvalidChar ELSE FirstSymbolChar + Ord [Sy]]};
CharToSymbol: PROC [Char: CHAR] RETURNS [Sy: Symbol] = INLINE
{IF Char IN [SymbolBaseChar .. LastSymbolChar) THEN
{Sy ← LOOPHOLE [Char - SymbolBaseChar, Symbol];
IF Sy = Num OR Sy = String THEN Sy ← Invalid}
ELSE
Sy ← Invalid};
-- LEXICAL AND SYNTACTICAL TABLES - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-- The table below distinguishes between operators (unary and binary) and other symbols. It gives also the "priority" and "associativity" of binary operators.
-- The priority increases as the numerical value of Prio decreases. If Assoc = TRUE, the operator can be mixed with other of same priority, and the expression will be evaluated from left to right. If Assoc = FALSE, there must be a parenthesis or equivalent somewhere between that operator and any other with the same priority.
-- Besides the "standard" character code defined above, a symbol usually has also an "alternate" representations (a string of letters or special characters). These are also given by the table below.
SymbolKind: TYPE = {UnOp, BinOp, Other};
SymbolProperties: TYPE = RECORD
[Alias: STRING,
Kind: SymbolKind ← Other,
Prio: Priority ← NULL,
Assoc: BOOLEAN ← NULL]
Props: ARRAY Symbol OF SymbolProperties =
[[Mod: ["mod", BinOp, 02, TRUE],
Mul: ["*", BinOp, 02, TRUE],
Div: ["/", BinOp, 02, TRUE],
Array: ["array", BinOp, 02, FALSE],
Cat: ["cat", BinOp, 03, TRUE],
Cut: ["cut", BinOp, 04, TRUE],
HMirror: ["hmir", BinOp, 04, TRUE],
RevRot: ["rrot", BinOp, 04, TRUE],
Rot: ["rot", BinOp, 04, TRUE],
Sample: ["sample", BinOp, 04, TRUE],
VMirror: ["vmir", BinOp, 04, TRUE],
Center: ["center", BinOp, 06, TRUE],
RevShift: ["rsh", BinOp, 06, TRUE],
Shift: ["sh", BinOp, 06, TRUE],
Add: ["+", BinOp, 06, TRUE],
Sub: ["-", BinOp, 06, TRUE],
Eql: ["=", BinOp, 08, FALSE],
GEq: [">=", BinOp, 08, FALSE],
GTr: [">", BinOp, 08, FALSE],
In: ["in", BinOp, 08, FALSE],
Is: ["?", BinOp, 08, FALSE],
LEq: ["<=", BinOp, 08, FALSE],
Lss: ["<", BinOp, 08, FALSE],
NEq: ["#", BinOp, 08, FALSE],
Xor: ["xor", BinOp, 09, TRUE],
Eqv: ["eqv", BinOp, 09, FALSE],
And: ["&", BinOp, 10, TRUE],
Erase: ["ers", BinOp, 10, TRUE],
Where: ["wh", BinOp, 10, FALSE],
Or: ["or", BinOp, 12, TRUE],
Over: ["over", BinOp, 12, TRUE],
From: ["fr", BinOp, 14, TRUE],
Depth: ["dp", BinOp, 14, TRUE],
Laminate: ["|", BinOp, 16, TRUE],
Blt: ["←", BinOp, 18, FALSE],
ReDef: [":=", BinOp, 20, TRUE],
ThenDo: [";", BinOp, 22, TRUE],
Box: ["box", UnOp],
Circle: ["circle", UnOp],
Count: ["count", UnOp],
DeRef: ["^", UnOp],
Ellipse: ["ellipse", UnOp],
Not: ["~", UnOp],
Opaque: ["opaque", UnOp],
Quote: ["'", UnOp],
Ref: ["@", UnOp],
Rep: ["rep", UnOp],
Triangle: ["tri", UnOp],
All: ["all", UnOp],
AndAlso: [","],
BegExpr: ["("],
BegParms: ["{"],
BegRec: ["["],
Cast: ["!"],
Def: [":"],
Do: ["do"],
Else: ["else"],
EndExpr: [")"],
EndParms: ["}"],
EndRec: ["]"],
For: ["for"],
Then: ["then"]];
-- PARSED EXPRESSION TREE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Expr: TYPE = RECORD
[Good: BOOLEAN,
Source: SourcePt,
Body: SELECT Kind: * FROM
Int => [Val: LONG INTEGER],
Id, String => [Chars: Rope.Ref],
Symbol => [Sy: Symbol],
Infix => [Op, Left, Right: RefExpr],
Cond => [Test, Then, Else: RefExpr],
Loop => [Var: REF Id Expr, Count, Test, Body: RefExpr],
Proc => [Parm: FieldExpr, Body: RefExpr],
RecExpr => [LS: LIST OF FieldExpr]
ENDCASE];
RefExpr: TYPE = REF Expr;
FieldExpr: TYPE = RECORD
[Name: REF Id Expr,
Val: RefExpr,
Mold: RefExpr];
-- THE PARSER (PHEW!) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Parse: PROCEDURE [T: Tail] RETURNS [EX: RefExpr, RT: Tail];
END.