|
@@ -0,0 +1,161 @@
|
|
|
|
|
+DEFINITION MODULE AST;
|
|
|
|
|
+(* Abstract syntax tree for m2compiler-V3 (Stage A: node store only).
|
|
|
|
|
+
|
|
|
|
|
+ This is the foundation for a two-phase frontend: productions build
|
|
|
|
|
+ nodes here while parsing, and a later walk resolves names and
|
|
|
|
|
+ lowers to QBE. Until the grammar is converted, nothing calls it.
|
|
|
|
|
+
|
|
|
|
|
+ Design notes
|
|
|
|
|
+ ------------
|
|
|
|
|
+ - Nodes live in a flat, pre-allocated arena and are referenced by an
|
|
|
|
|
+ integer index (`Node`), exactly like `SymTab.TypeIndex`. This
|
|
|
|
|
+ avoids pointers in the interface and keeps the structure
|
|
|
|
|
+ self-hosting-friendly (no GC, bounded memory).
|
|
|
|
|
+ - Every node has a `kind` (NKind) and a `ty` (a SymTab.TypeIndex set
|
|
|
|
|
+ by the checker), plus up to `MaxChild` children. This mirrors the
|
|
|
|
|
+ `armornick/CocoR` AST.java pattern (a Node base with per-construct
|
|
|
|
|
+ subclasses) but flattened into one record array so Modula-2 can
|
|
|
|
|
+ store it without variant-class machinery.
|
|
|
|
|
+ - Text (identifiers, literals, operator spellings) is kept in a
|
|
|
|
|
+ pooled string table; `TxtIndex` is an index into it.
|
|
|
|
|
+ - `NoNode` is the null node. *)
|
|
|
|
|
+
|
|
|
|
|
+CONST
|
|
|
|
|
+ NoNode = -1;
|
|
|
|
|
+ NoTxt = -1;
|
|
|
|
|
+
|
|
|
|
|
+ (* how many children a node may carry. Statements/expressions in
|
|
|
|
|
+ Modula-2 nest shallowly (a body is a list, an expression is a
|
|
|
|
|
+ spine); 8 covers every construct in the current grammar with room
|
|
|
|
|
+ to spare. *)
|
|
|
|
|
+ MaxChild = 8;
|
|
|
|
|
+
|
|
|
|
|
+ (* ---- node kinds ----
|
|
|
|
|
+ Grouped by role; the numeric values are stable and may be stored
|
|
|
|
|
+ in listings. *)
|
|
|
|
|
+
|
|
|
|
|
+ (* module / unit structure *)
|
|
|
|
|
+ NkUnit = 0; (* [0]=name txt, [1]=decls, [2]=body *)
|
|
|
|
|
+ NkDefUnit = 1;
|
|
|
|
|
+ NkImplUnit = 2;
|
|
|
|
|
+ NkDeclSeq = 3; (* [0..n)=declarations *)
|
|
|
|
|
+ NkImport = 4; (* [0]=module txt, [1..n)=names (or FROM list) *)
|
|
|
|
|
+
|
|
|
|
|
+ (* declarations *)
|
|
|
|
|
+ NkConstDecl = 10; (* [0]=name txt, [1]=value expr *)
|
|
|
|
|
+ NkTypeDecl = 11; (* [0]=name txt, [1]=type *)
|
|
|
|
|
+ NkVarDecl = 12; (* [0..n)=name txt, [1]=type (names then type) *)
|
|
|
|
|
+ NkProcDecl = 13; (* [0]=name, [1]=formals, [2]=result type,
|
|
|
|
|
+ [3]=body, [4]=forward flag node *)
|
|
|
|
|
+ NkClassDecl = 14;
|
|
|
|
|
+ NkFieldDecl = 15;
|
|
|
|
|
+
|
|
|
|
|
+ (* type constructors *)
|
|
|
|
|
+ NkTypeIdent = 20; (* [0]=name txt (possibly qualified: a.b) *)
|
|
|
|
|
+ NkSubrange = 21; (* [0]=lo expr, [1]=hi expr *)
|
|
|
|
|
+ NkEnum = 22; (* [0..n)=literal name txts *)
|
|
|
|
|
+ NkArray = 23; (* [0..n-2)=index types, [last]=element type *)
|
|
|
|
|
+ NkRecord = 24; (* [0..n)=fields *)
|
|
|
|
|
+ NkSet = 25; (* [0]=base type *)
|
|
|
|
|
+ NkPointer = 26; (* [0]=base type *)
|
|
|
|
|
+ NkProcType = 27; (* [0]=formals, [1]=result type *)
|
|
|
|
|
+
|
|
|
|
|
+ (* statements *)
|
|
|
|
|
+ NkAssign = 40; (* [0]=designator, [1]=value *)
|
|
|
|
|
+ NkCall = 41; (* [0]=callee, [1..n)=actuals *)
|
|
|
|
|
+ NkIf = 42; (* [0]=cond, [1]=then, [2]=else (or NoNode) *)
|
|
|
|
|
+ NkWhile = 43; (* [0]=cond, [1]=body *)
|
|
|
|
|
+ NkRepeat = 44; (* [0]=body, [1]=until cond *)
|
|
|
|
|
+ NkLoop = 45; (* [0]=body *)
|
|
|
|
|
+ NkExit = 46;
|
|
|
|
|
+ NkFor = 47; (* [0]=control var, [1]=lo, [2]=hi, [3]=by, [4]=body *)
|
|
|
|
|
+ NkCase = 48; (* [0]=selector, [1..n)=case arms *)
|
|
|
|
|
+ NkCaseArm = 49; (* [0..n-1)=labels, [n]=body *)
|
|
|
|
|
+ NkWith = 50; (* [0..n-1)=designators, [n]=body *)
|
|
|
|
|
+ NkReturn = 51; (* [0]=expr (or NoNode) *)
|
|
|
|
|
+ NkBlock = 52; (* [0..n)=statements *)
|
|
|
|
|
+ NkHalt = 53;
|
|
|
|
|
+
|
|
|
|
|
+ (* expressions *)
|
|
|
|
|
+ NkBinExpr = 70; (* [0]=left, [1]=right; `op` holds the operator *)
|
|
|
|
|
+ NkUnary = 71; (* [0]=operand; `op` holds the operator *)
|
|
|
|
|
+ NkDesignator = 72; (* [0]=base, [1..n)=selectors *)
|
|
|
|
|
+ NkSelector = 73; (* .field / [idx] / ^ ; `op` distinguishes *)
|
|
|
|
|
+ NkIdent = 74; (* [0]=name txt, [1]=qualifier txt (or NoTxt) *)
|
|
|
|
|
+ NkIntLit = 75; (* [0]=digits txt *)
|
|
|
|
|
+ NkRealLit = 76;
|
|
|
|
|
+ NkStrLit = 77;
|
|
|
|
|
+ NkCharLit = 78;
|
|
|
|
|
+ NkBraceLit = 79; (* [0]=type, [1..n)=elements *)
|
|
|
|
|
+ NkSetLit = 80;
|
|
|
|
|
+
|
|
|
|
|
+ (* ---- relational / arithmetic / selector operator codes ---- *)
|
|
|
|
|
+ OpAdd = 0; OpSub = 1; OpOr = 2;
|
|
|
|
|
+ OpMul = 3; OpDiv = 4; OpMod = 5; OpAnd = 6;
|
|
|
|
|
+ OpEq = 7; OpNe = 8; OpLt = 9; OpLe = 10; OpGt = 11; OpGe = 12;
|
|
|
|
|
+ OpIn = 13;
|
|
|
|
|
+
|
|
|
|
|
+ (* selector codes (NkSelector.op) *)
|
|
|
|
|
+ SelField = 0; SelIndex = 1; SelDeref = 2;
|
|
|
|
|
+
|
|
|
|
|
+ TYPE
|
|
|
|
|
+ Node = INTEGER; (* index into the arena, or NoNode *)
|
|
|
|
|
+ TxtIndex = INTEGER; (* index into the text pool, or NoTxt *)
|
|
|
|
|
+
|
|
|
|
|
+ (* ---------------- lifecycle ---------------- *)
|
|
|
|
|
+
|
|
|
|
|
+PROCEDURE Init;
|
|
|
|
|
+(* Clears the arena and text pool. *)
|
|
|
|
|
+
|
|
|
|
|
+ (* ---------------- text pool ---------------- *)
|
|
|
|
|
+
|
|
|
|
|
+PROCEDURE AddTxt (s : ARRAY OF CHAR) : TxtIndex;
|
|
|
|
|
+(* Interns s, returning its index (deduplicated). *)
|
|
|
|
|
+
|
|
|
|
|
+PROCEDURE Txt (i : TxtIndex; VAR s : ARRAY OF CHAR);
|
|
|
|
|
+(* Copies the i-th text into s (empty when out of range). *)
|
|
|
|
|
+
|
|
|
|
|
+PROCEDURE TxtLen (i : TxtIndex) : CARDINAL;
|
|
|
|
|
+
|
|
|
|
|
+ (* ---------------- node construction ---------------- *)
|
|
|
|
|
+
|
|
|
|
|
+PROCEDURE MakeNode (kind : INTEGER) : Node;
|
|
|
|
|
+(* A fresh node of the given kind, no children, ty = SymTab.InvalidType
|
|
|
|
|
+ (the caller sets it). NoNode when the arena is full. *)
|
|
|
|
|
+
|
|
|
|
|
+PROCEDURE MakeLeaf (kind : INTEGER; name : ARRAY OF CHAR) : Node;
|
|
|
|
|
+(* A fresh node with child[0] set to the interned text of name. *)
|
|
|
|
|
+
|
|
|
|
|
+PROCEDURE MakeBin (kind, op : INTEGER; l, r : Node) : Node;
|
|
|
|
|
+(* A fresh node with op and two children (binary expr, assign, …). *)
|
|
|
|
|
+
|
|
|
|
|
+PROCEDURE MakeUn (kind, op : INTEGER; e : Node) : Node;
|
|
|
|
|
+(* A fresh node with op and one child (unary expr, selector, …). *)
|
|
|
|
|
+
|
|
|
|
|
+ (* ---------------- node accessors ---------------- *)
|
|
|
|
|
+
|
|
|
|
|
+PROCEDURE Kind (n : Node) : INTEGER;
|
|
|
|
|
+PROCEDURE SetKind (n : Node; kind : INTEGER);
|
|
|
|
|
+
|
|
|
|
|
+PROCEDURE Op (n : Node) : INTEGER;
|
|
|
|
|
+PROCEDURE SetOp (n : Node; op : INTEGER);
|
|
|
|
|
+
|
|
|
|
|
+PROCEDURE Ty (n : Node) : INTEGER;
|
|
|
|
|
+(* The SymTab.TypeIndex attached by the checker (InvalidType until
|
|
|
|
|
+ then). Declared as INTEGER to avoid a circular import with
|
|
|
|
|
+ SymTab. *)
|
|
|
|
|
+PROCEDURE SetTy (n : Node; t : INTEGER);
|
|
|
|
|
+
|
|
|
|
|
+PROCEDURE NChild (n : Node) : CARDINAL;
|
|
|
|
|
+PROCEDURE Child (n : Node; i : CARDINAL) : Node;
|
|
|
|
|
+PROCEDURE AddChild (n : Node; c : Node) : BOOLEAN;
|
|
|
|
|
+PROCEDURE SetChild (n : Node; i : CARDINAL; c : Node);
|
|
|
|
|
+(* Replaces child i, extending the node when i = NChild. *)
|
|
|
|
|
+
|
|
|
|
|
+ (* ---------------- listing (debug) ---------------- *)
|
|
|
|
|
+
|
|
|
|
|
+PROCEDURE Dump (n : Node; depth : CARDINAL);
|
|
|
|
|
+(* Writes a one-line-per-node indented tree to StdOut (via FileIO).
|
|
|
|
|
+ Used by the Stage-A self-test and future debugging. *)
|
|
|
|
|
+
|
|
|
|
|
+END AST.
|