| (* M2ALU.mod gcc implementation of the M2ALU module. |
| |
| Copyright (C) 2001-2025 Free Software Foundation, Inc. |
| Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>. |
| |
| This file is part of GNU Modula-2. |
| |
| GNU Modula-2 is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GNU Modula-2 is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Modula-2; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. *) |
| |
| IMPLEMENTATION MODULE M2ALU ; |
| |
| (* |
| Title : M2ALU.mod |
| Author : Gaius Mulley |
| System : UNIX (gm2) |
| Date : Mon Jul 10 12:04:50 2000 |
| Description: gcc implementation of the M2ALU module, this module provides an interface |
| between some of the Modula-2 front end optimization routines and tree |
| construction required so that efficient trees can be passed to gcc's |
| backend. M2ALU allows constant expressions to be calculated. |
| *) |
| |
| FROM ASCII IMPORT nul ; |
| FROM SYSTEM IMPORT WORD, ADDRESS ; |
| FROM NameKey IMPORT KeyToCharStar, MakeKey, CharKey ; |
| FROM M2Error IMPORT InternalError, FlushErrors ; |
| FROM M2Debug IMPORT Assert ; |
| FROM Storage IMPORT ALLOCATE ; |
| FROM StringConvert IMPORT ostoi, bstoi, stoi, hstoi ; |
| FROM M2GCCDeclare IMPORT GetTypeMin, GetTypeMax, CompletelyResolved, DeclareConstant ; |
| FROM M2GenGCC IMPORT PrepareCopyString, StringToChar ; |
| FROM M2Bitset IMPORT Bitset ; |
| FROM SymbolConversion IMPORT Mod2Gcc, GccKnowsAbout ; |
| FROM M2Printf IMPORT printf0, printf2 ; |
| FROM M2Base IMPORT MixTypes, GetBaseTypeMinMax, Char, IsRealType, IsComplexType, ZType ; |
| FROM DynamicStrings IMPORT String, InitString, Mark, ConCat, Slice, InitStringCharStar, KillString, InitStringChar, string ; |
| FROM M2LexBuf IMPORT TokenToLineNo, FindFileNameFromToken, TokenToLocation ; |
| FROM M2MetaError IMPORT MetaError0, MetaError1, MetaError2, MetaErrorStringT0, |
| MetaErrorT0, MetaErrorT1, MetaErrorT2, MetaErrorT3 ; |
| |
| FROM SymbolTable IMPORT NulSym, IsEnumeration, IsSubrange, IsValueSolved, PushValue, |
| ForeachFieldEnumerationDo, MakeTemporary, PutVar, PopValue, GetType, |
| MakeConstLit, GetArraySubscript, |
| IsSet, SkipType, IsRecord, IsArray, IsConst, IsConstructor, |
| IsConstString, SkipTypeAndSubrange, GetDeclaredMod, |
| GetSubrange, GetSymName, GetNth, GetString, GetStringLength, |
| ModeOfAddr ; |
| |
| IMPORT DynamicStrings ; |
| |
| FROM gcctypes IMPORT location_t, tree ; |
| FROM m2linemap IMPORT UnknownLocation ; |
| |
| FROM m2expr IMPORT BuildAdd, BuildSub, BuildMult, |
| BuildDivTrunc, BuildModTrunc, BuildDivFloor, BuildModFloor, |
| BuildLSL, BuildLSR, |
| BuildLogicalOr, BuildLogicalAnd, BuildSymmetricDifference, |
| GetWordOne, GetCardinalZero, TreeOverflow, RemoveOverflow, |
| GetCstInteger ; |
| |
| FROM m2decl IMPORT GetBitsPerBitset, BuildIntegerConstant, BuildConstLiteralNumber ; |
| FROM m2misc IMPORT DebugTree ; |
| |
| FROM m2type IMPORT RealToTree, Constructor, GetIntegerType, GetLongRealType, |
| BuildStartSetConstructor, BuildSetConstructorElement, BuildEndSetConstructor, |
| BuildRecordConstructorElement, BuildEndRecordConstructor, BuildStartRecordConstructor, |
| BuildNumberOfArrayElements, BuildCharConstant, BuildCharConstantChar, |
| BuildArrayConstructorElement, BuildStartArrayConstructor, BuildEndArrayConstructor, |
| GetM2CharType ; |
| |
| FROM m2convert IMPORT ConvertConstantAndCheck, ToWord, ToInteger, ToCardinal, ToBitset ; |
| FROM m2block IMPORT RememberConstant ; |
| |
| FROM m2expr IMPORT GetPointerZero, GetIntegerZero, GetIntegerOne, |
| CompareTrees, FoldAndStrip, AreRealOrComplexConstantsEqual, AreConstantsEqual ; |
| |
| |
| TYPE |
| cellType = (none, integer, real, complex, set, constructor, array, record) ; |
| |
| |
| CONST |
| Debugging = FALSE ; |
| DebugGarbage = TRUE ; |
| |
| TYPE |
| listOfRange = POINTER TO rList ; |
| rList = RECORD |
| low, high: CARDINAL ; (* symbol table *) |
| next : listOfRange ; |
| END ; |
| |
| listOfFields = POINTER TO fList ; |
| fList = RECORD |
| field : CARDINAL ; (* symbol table *) |
| next : listOfFields ; |
| END ; |
| |
| listOfElements = POINTER TO eList ; |
| eList = RECORD |
| element : CARDINAL ; (* symbol table *) |
| by : CARDINAL ; (* symbol table *) |
| next : listOfElements ; |
| END ; |
| |
| PtrToValue = POINTER TO cell ; |
| cell = RECORD |
| location : location_t ; |
| areAllConstants, |
| solved : BOOLEAN ; |
| constructorType: CARDINAL ; |
| next : PtrToValue ; |
| numberValue : tree ; |
| |
| CASE type: cellType OF |
| |
| none, |
| integer, real, |
| complex : | |
| set : setValue : listOfRange | |
| constructor, |
| record : fieldValues: listOfFields | |
| array : arrayValues: listOfElements |
| |
| END |
| END ; |
| |
| DoSetProcedure = PROCEDURE (CARDINAL, listOfRange, listOfRange) : listOfRange ; |
| |
| |
| VAR |
| ElementFreeList : listOfElements ; |
| FieldFreeList : listOfFields ; |
| RangeFreeList : listOfRange ; |
| FreeList, |
| TopOfStack : PtrToValue ; |
| EnumerationValue: tree ; |
| EnumerationField: CARDINAL ; |
| CurrentTokenNo : CARDINAL ; |
| (* WatchedValue : PtrToValue ; *) |
| |
| |
| (* |
| New - allocate a PtrToValue. Firstly check the FreeList, if empty call upon New. |
| *) |
| |
| PROCEDURE New () : PtrToValue ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| IF FreeList=NIL |
| THEN |
| NEW (v) |
| ELSE |
| v := FreeList ; |
| FreeList := FreeList^.next |
| END ; |
| WITH v^ DO |
| numberValue := NIL |
| END ; |
| RETURN InitRecord (v) |
| END New ; |
| |
| |
| (* |
| InitRecord - initialize the non variant fields of, v. Return v. |
| *) |
| |
| PROCEDURE InitRecord (v: PtrToValue) : PtrToValue ; |
| BEGIN |
| WITH v^ DO |
| location := UnknownLocation () ; |
| areAllConstants := FALSE ; |
| solved := FALSE ; |
| constructorType := NulSym ; |
| numberValue := NIL |
| END ; |
| RETURN v |
| END InitRecord ; |
| |
| |
| (* |
| NewRange - assigns, v, to a new area of memory. |
| *) |
| |
| PROCEDURE NewRange (VAR v: listOfRange) ; |
| BEGIN |
| IF RangeFreeList=NIL |
| THEN |
| NEW(v) ; |
| IF v=NIL |
| THEN |
| InternalError ('out of memory error') |
| END |
| ELSE |
| v := RangeFreeList ; |
| RangeFreeList := RangeFreeList^.next |
| END |
| END NewRange ; |
| |
| |
| (* |
| DisposeRange - adds the list, v, to the free list. |
| *) |
| |
| PROCEDURE DisposeRange (VAR v: listOfRange) ; |
| VAR |
| r: listOfRange ; |
| BEGIN |
| IF v#NIL |
| THEN |
| r := v ; |
| WHILE (r#NIL) AND (r^.next#NIL) DO |
| r := r^.next |
| END ; |
| IF r#NIL |
| THEN |
| r^.next := RangeFreeList |
| END ; |
| RangeFreeList := v ; |
| v := NIL |
| END |
| END DisposeRange ; |
| |
| |
| (* |
| IsOnFieldFreeList - returns TRUE if, r, is on the FieldFreeList. |
| *) |
| |
| PROCEDURE IsOnFieldFreeList (r: listOfFields) : BOOLEAN ; |
| VAR |
| s: listOfFields ; |
| BEGIN |
| s := FieldFreeList ; |
| WHILE s#NIL DO |
| IF s=r |
| THEN |
| RETURN( TRUE ) |
| ELSE |
| s := s^.next |
| END |
| END ; |
| RETURN( FALSE ) |
| END IsOnFieldFreeList ; |
| |
| |
| (* |
| IsOnElementFreeList - returns TRUE if, r, is on the ElementFreeList. |
| *) |
| |
| PROCEDURE IsOnElementFreeList (r: listOfElements) : BOOLEAN ; |
| VAR |
| s: listOfElements ; |
| BEGIN |
| s := ElementFreeList ; |
| WHILE s#NIL DO |
| IF s=r |
| THEN |
| RETURN( TRUE ) |
| ELSE |
| s := s^.next |
| END |
| END ; |
| RETURN( FALSE ) |
| END IsOnElementFreeList ; |
| |
| |
| (* |
| DisposeFields - adds the list, v, to the free list. |
| *) |
| |
| PROCEDURE DisposeFields (VAR v: listOfFields) ; |
| VAR |
| r: listOfFields ; |
| BEGIN |
| IF v#NIL |
| THEN |
| r := v ; |
| WHILE r^.next#NIL DO |
| Assert(NOT IsOnFieldFreeList(r)) ; |
| r := r^.next |
| END ; |
| r^.next := FieldFreeList ; |
| FieldFreeList := v ; |
| v := NIL |
| END |
| END DisposeFields ; |
| |
| |
| (* |
| NewField - adds the list, v, to the free list. |
| *) |
| |
| PROCEDURE NewField (VAR v: listOfFields) ; |
| BEGIN |
| IF FieldFreeList=NIL |
| THEN |
| NEW(v) ; |
| IF v=NIL |
| THEN |
| InternalError ('out of memory error') |
| END |
| ELSE |
| v := FieldFreeList ; |
| FieldFreeList := FieldFreeList^.next |
| END |
| END NewField ; |
| |
| |
| (* |
| NewElement - returns a new element record. |
| *) |
| |
| PROCEDURE NewElement (VAR e: listOfElements) ; |
| BEGIN |
| IF ElementFreeList=NIL |
| THEN |
| NEW(e) ; |
| IF e=NIL |
| THEN |
| InternalError ('out of memory error') |
| END |
| ELSE |
| e := ElementFreeList ; |
| ElementFreeList := ElementFreeList^.next |
| END |
| END NewElement ; |
| |
| |
| (* |
| DisposeElements - returns the list, e, to the free list. |
| *) |
| |
| PROCEDURE DisposeElements (VAR e: listOfElements) ; |
| VAR |
| r: listOfElements ; |
| BEGIN |
| IF e#NIL |
| THEN |
| r := e ; |
| WHILE r^.next#NIL DO |
| Assert(NOT IsOnElementFreeList(r)) ; |
| r := r^.next |
| END ; |
| r^.next := ElementFreeList ; |
| ElementFreeList := e ; |
| e := NIL |
| END |
| END DisposeElements ; |
| |
| |
| (* |
| CheckNotAlreadyOnFreeList - checks to see whether, v, is already on the free list |
| and aborts if this is the case. |
| *) |
| |
| PROCEDURE CheckNotAlreadyOnFreeList (v: PtrToValue) ; |
| VAR |
| l: PtrToValue ; |
| BEGIN |
| IF DebugGarbage |
| THEN |
| l := FreeList ; |
| WHILE l#NIL DO |
| IF l=v |
| THEN |
| InternalError ('value is already on the free list') |
| END ; |
| l := l^.next |
| END |
| END |
| END CheckNotAlreadyOnFreeList ; |
| |
| |
| (* |
| CheckNotOnStack - checks to see whether, v, is already on the stack |
| and aborts if this is the case. |
| *) |
| |
| PROCEDURE CheckNotOnStack (v: PtrToValue) ; |
| VAR |
| l: PtrToValue ; |
| BEGIN |
| IF DebugGarbage |
| THEN |
| l := TopOfStack ; |
| WHILE l#NIL DO |
| IF l=v |
| THEN |
| InternalError ('value is already on the stack') |
| END ; |
| l := l^.next |
| END |
| END |
| END CheckNotOnStack ; |
| |
| |
| (* |
| Dispose - place, v, onto the FreeList. |
| *) |
| |
| PROCEDURE Dispose (v: PtrToValue) ; |
| BEGIN |
| CheckNotAlreadyOnFreeList(v) ; |
| CheckNotOnStack(v) ; |
| CASE v^.type OF |
| |
| set : DisposeRange(v^.setValue) | |
| constructor, |
| record : DisposeFields(v^.fieldValues) | |
| array : DisposeElements(v^.arrayValues) |
| |
| ELSE |
| END ; |
| v^.next := FreeList ; |
| FreeList := v |
| END Dispose ; |
| |
| |
| (* |
| AddRange - returns a ListOfRange which is prepended to the front of the current list. |
| *) |
| |
| PROCEDURE AddRange (head: listOfRange; l, h: CARDINAL) : listOfRange ; |
| VAR |
| r: listOfRange ; |
| BEGIN |
| NewRange(r) ; |
| WITH r^ DO |
| low := l ; |
| high := h ; |
| next := head |
| END ; |
| RETURN( r ) |
| END AddRange ; |
| |
| |
| (* |
| DupRange - duplicates and returns the list, t. |
| *) |
| |
| PROCEDURE DupRange (r: listOfRange) : listOfRange ; |
| VAR |
| s: listOfRange ; |
| BEGIN |
| s := NIL ; |
| WHILE r#NIL DO |
| s := AddRange(s, r^.low, r^.high) ; |
| r := r^.next |
| END ; |
| RETURN( s ) |
| END DupRange ; |
| |
| |
| (* |
| InitValue - initializes and returns a memory cell. |
| *) |
| |
| PROCEDURE InitValue () : PtrToValue ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := New() ; |
| IF v=NIL |
| THEN |
| InternalError ('out of memory error') |
| ELSE |
| WITH v^ DO |
| location := UnknownLocation () ; |
| type := none ; |
| areAllConstants := TRUE ; |
| solved := FALSE ; |
| next := NIL ; |
| constructorType := NulSym |
| END ; |
| RETURN( v ) |
| END |
| END InitValue ; |
| |
| |
| (* |
| IsValueTypeNone - returns TRUE if the value on the top stack has no value. |
| *) |
| |
| PROCEDURE IsValueTypeNone () : BOOLEAN ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=none |
| THEN |
| Push(v) ; |
| RETURN( TRUE ) |
| ELSE |
| Push(v) ; |
| RETURN( FALSE ) |
| END |
| END |
| END IsValueTypeNone ; |
| |
| |
| (* |
| IsValueTypeInteger - returns TRUE if the value on the top stack is an integer. |
| *) |
| |
| PROCEDURE IsValueTypeInteger () : BOOLEAN ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=integer |
| THEN |
| Push(v) ; |
| RETURN( TRUE ) |
| ELSE |
| Push(v) ; |
| RETURN( FALSE ) |
| END |
| END |
| END IsValueTypeInteger ; |
| |
| |
| (* |
| IsValueTypeReal - returns TRUE if the value on the top stack is a real. |
| *) |
| |
| PROCEDURE IsValueTypeReal () : BOOLEAN ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=real |
| THEN |
| Push(v) ; |
| RETURN( TRUE ) |
| ELSE |
| Push(v) ; |
| RETURN( FALSE ) |
| END |
| END |
| END IsValueTypeReal ; |
| |
| |
| (* |
| IsValueTypeComplex - returns TRUE if the value on the top stack is a complex. |
| *) |
| |
| PROCEDURE IsValueTypeComplex () : BOOLEAN ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=complex |
| THEN |
| Push(v) ; |
| RETURN( TRUE ) |
| ELSE |
| Push(v) ; |
| RETURN( FALSE ) |
| END |
| END |
| END IsValueTypeComplex ; |
| |
| |
| (* |
| IsValueTypeSet - returns TRUE if the value on the top stack is a set. |
| *) |
| |
| PROCEDURE IsValueTypeSet () : BOOLEAN ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=set |
| THEN |
| Push(v) ; |
| RETURN( TRUE ) |
| ELSE |
| Push(v) ; |
| RETURN( FALSE ) |
| END |
| END |
| END IsValueTypeSet ; |
| |
| |
| (* |
| IsValueTypeConstructor - returns TRUE if the value on the top |
| stack is a constructor. |
| *) |
| |
| PROCEDURE IsValueTypeConstructor () : BOOLEAN ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=constructor |
| THEN |
| Push(v) ; |
| RETURN( TRUE ) |
| ELSE |
| Push(v) ; |
| RETURN( FALSE ) |
| END |
| END |
| END IsValueTypeConstructor ; |
| |
| |
| (* |
| IsValueTypeArray - returns TRUE if the value on the top stack is |
| an array. |
| *) |
| |
| PROCEDURE IsValueTypeArray () : BOOLEAN ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=array |
| THEN |
| Push(v) ; |
| RETURN( TRUE ) |
| ELSE |
| Push(v) ; |
| RETURN( FALSE ) |
| END |
| END |
| END IsValueTypeArray ; |
| |
| |
| (* |
| IsValueTypeRecord - returns TRUE if the value on the top stack is |
| a record. |
| *) |
| |
| PROCEDURE IsValueTypeRecord () : BOOLEAN ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=record |
| THEN |
| Push(v) ; |
| RETURN( TRUE ) |
| ELSE |
| Push(v) ; |
| RETURN( FALSE ) |
| END |
| END |
| END IsValueTypeRecord ; |
| |
| |
| (* |
| GetSetValueType - returns the set type on top of the ALU stack. |
| *) |
| |
| PROCEDURE GetSetValueType () : CARDINAL ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| Push(v) ; |
| WITH v^ DO |
| IF type=set |
| THEN |
| RETURN( constructorType ) |
| ELSE |
| InternalError ('expecting set type') |
| END |
| END |
| END GetSetValueType ; |
| |
| |
| (* |
| PushIntegerTree - pushes a gcc tree value onto the ALU stack. |
| *) |
| |
| PROCEDURE PushIntegerTree (t: tree) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := InitValue() ; |
| WITH v^ DO |
| type := integer ; |
| numberValue := t ; |
| areAllConstants := TRUE ; |
| solved := TRUE |
| END ; |
| Push(v) |
| END PushIntegerTree ; |
| |
| |
| (* |
| PopIntegerTree - pops a gcc tree value from the ALU stack. |
| *) |
| |
| PROCEDURE PopIntegerTree () : tree ; |
| VAR |
| v: PtrToValue ; |
| t: tree ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=integer |
| THEN |
| t := numberValue |
| ELSE |
| InternalError ('expecting type of constant to be a whole number') |
| END |
| END ; |
| Dispose(v) ; |
| RETURN( t ) |
| END PopIntegerTree ; |
| |
| |
| (* |
| PushRealTree - pushes a gcc tree value onto the ALU stack. |
| *) |
| |
| PROCEDURE PushRealTree (t: tree) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := New() ; |
| WITH v^ DO |
| type := real ; |
| numberValue := t ; |
| areAllConstants := TRUE ; |
| solved := TRUE |
| END ; |
| Push(v) |
| END PushRealTree ; |
| |
| |
| (* |
| PopRealTree - pops a gcc tree value from the ALU stack. |
| *) |
| |
| PROCEDURE PopRealTree () : tree ; |
| VAR |
| v: PtrToValue ; |
| t: tree ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=real |
| THEN |
| t := numberValue |
| ELSE |
| InternalError ('expecting type of constant to be a real number') |
| END |
| END ; |
| Dispose(v) ; |
| RETURN( t ) |
| END PopRealTree ; |
| |
| |
| (* |
| PushComplexTree - pushes a gcc tree value onto the ALU stack. |
| *) |
| |
| PROCEDURE PushComplexTree (t: tree) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := New() ; |
| WITH v^ DO |
| type := complex ; |
| numberValue := t ; |
| areAllConstants := TRUE ; |
| solved := TRUE |
| END ; |
| Push(v) |
| END PushComplexTree ; |
| |
| |
| (* |
| PopComplexTree - pops a gcc tree value from the ALU stack. |
| *) |
| |
| PROCEDURE PopComplexTree () : tree ; |
| VAR |
| v: PtrToValue ; |
| t: tree ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=complex |
| THEN |
| t := numberValue |
| ELSE |
| InternalError ('expecting type of constant to be a complex number') |
| END |
| END ; |
| Dispose(v) ; |
| RETURN( t ) |
| END PopComplexTree ; |
| |
| |
| (* |
| PushSetTree - pushes a gcc tree onto the ALU stack. |
| The tree, t, is expected to contain a |
| word value. It is converted into a set |
| type (sym). Bit 0 maps onto MIN(sym). |
| *) |
| |
| PROCEDURE PushSetTree (tokenno: CARDINAL; |
| t: tree; sym: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| c, |
| i: INTEGER ; |
| r: listOfRange ; |
| l: location_t ; |
| BEGIN |
| l := TokenToLocation(tokenno) ; |
| r := NIL ; |
| i := 0 ; |
| WHILE (i<GetBitsPerBitset()) AND |
| (CompareTrees(GetIntegerZero(l), t)#0) DO |
| IF CompareTrees(GetIntegerOne(l), |
| BuildLogicalAnd(l, t, GetIntegerOne(l), FALSE))=0 |
| THEN |
| PushCard(i) ; |
| c := Val(tokenno, SkipType(sym), PopIntegerTree()) ; |
| DeclareConstant(tokenno, c) ; |
| r := AddRange(r, c, c) |
| END ; |
| t := BuildLSR(l, t, GetIntegerOne(l), FALSE) ; |
| INC(i) |
| END ; |
| SortElements(tokenno, r) ; |
| CombineElements(tokenno, r) ; |
| v := New() ; |
| WITH v^ DO |
| location := l ; |
| type := set ; |
| constructorType := sym ; |
| areAllConstants := FALSE ; |
| solved := FALSE ; |
| setValue := r |
| END ; |
| Eval(tokenno, v) ; |
| Push(v) |
| END PushSetTree ; |
| |
| |
| (* |
| PopSetTree - pops a gcc tree from the ALU stack. |
| *) |
| |
| PROCEDURE PopSetTree (tokenno: CARDINAL) : tree ; |
| VAR |
| v: PtrToValue ; |
| t: tree ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=set |
| THEN |
| Eval(tokenno, v) ; |
| IF NOT v^.solved |
| THEN |
| InternalError ('the set has not been resolved') |
| END ; |
| IF NOT v^.areAllConstants |
| THEN |
| InternalError ('the set must only contain constants') |
| END ; |
| t := ConstructSetConstant(tokenno, v) |
| ELSE |
| InternalError ('expecting type of constant to be a set') |
| END |
| END ; |
| Dispose(v) ; |
| RETURN( t ) |
| END PopSetTree ; |
| |
| |
| (* |
| PopConstructorTree - returns a tree containing the compound literal. |
| *) |
| |
| PROCEDURE PopConstructorTree (tokenno: CARDINAL) : tree ; |
| VAR |
| v: PtrToValue ; |
| t: tree ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| Eval(tokenno, v) ; |
| IF NOT v^.solved |
| THEN |
| InternalError ('the constructor has not been resolved') |
| END ; |
| CASE type OF |
| |
| constructor: InternalError('expecting constructor to be resolved into specific type') | |
| array : t := ConstructArrayConstant(tokenno, v) | |
| record : t := ConstructRecordConstant(tokenno, v) | |
| set : t := ConstructSetConstant(tokenno, v) |
| |
| ELSE |
| InternalError ('expecting type to be a constructor') |
| END |
| END ; |
| Dispose(v) ; |
| RETURN( t ) |
| END PopConstructorTree ; |
| |
| |
| (* |
| Pop - pops and returns top element from the stack. |
| *) |
| |
| PROCEDURE Pop () : PtrToValue ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| IF TopOfStack=NIL |
| THEN |
| InternalError ('stack underflow error') |
| ELSE |
| v := TopOfStack ; |
| TopOfStack := TopOfStack^.next |
| END ; |
| CheckNotAlreadyOnFreeList(v) ; |
| RETURN( v ) |
| END Pop ; |
| |
| |
| (* |
| Push - pushes the value onto the stack. |
| *) |
| |
| PROCEDURE Push (v: PtrToValue) ; |
| BEGIN |
| CheckNotAlreadyOnFreeList(v) ; |
| CheckNotOnStack(v) ; |
| v^.next := TopOfStack ; |
| TopOfStack := v |
| END Push ; |
| |
| |
| (* |
| Reduce - remove the top element of the stack. |
| *) |
| |
| PROCEDURE Reduce ; |
| BEGIN |
| Dispose (Pop ()) |
| END Reduce ; |
| |
| |
| (* |
| PrintValue - debugging procedure to display the value on the top of the stack. |
| *) |
| |
| PROCEDURE PrintValue ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=integer |
| THEN |
| DebugTree(numberValue) |
| END |
| END ; |
| Push(v) |
| END PrintValue ; |
| |
| |
| (* |
| DupFields - duplicates the field list in order. |
| *) |
| |
| PROCEDURE DupFields (f: listOfFields) : listOfFields ; |
| VAR |
| p, q, l: listOfFields ; |
| BEGIN |
| p := NIL ; |
| l := NIL ; |
| WHILE f#NIL DO |
| NewField(q) ; |
| IF p=NIL |
| THEN |
| p := q |
| END ; |
| q^.field := f^.field ; |
| q^.next := NIL ; |
| IF l#NIL |
| THEN |
| l^.next := q |
| END ; |
| l := q ; |
| f := f^.next |
| END ; |
| RETURN( p ) |
| END DupFields ; |
| |
| |
| (* |
| DupElements - duplicates the array list in order. |
| *) |
| |
| PROCEDURE DupElements (f: listOfElements) : listOfElements ; |
| VAR |
| p, q, l: listOfElements ; |
| BEGIN |
| p := NIL ; |
| l := NIL ; |
| WHILE f#NIL DO |
| NewElement(q) ; |
| IF p=NIL |
| THEN |
| p := q |
| END ; |
| q^.element := f^.element ; |
| q^.by := f^.by ; |
| q^.next := NIL ; |
| IF l#NIL |
| THEN |
| l^.next := q |
| END ; |
| l := q ; |
| f := f^.next |
| END ; |
| RETURN( p ) |
| END DupElements ; |
| |
| |
| (* |
| PushFrom - pushes a copy of the contents of, v, onto stack. |
| *) |
| |
| PROCEDURE PushFrom (v: PtrToValue) ; |
| VAR |
| t: PtrToValue ; |
| BEGIN |
| CheckNotAlreadyOnFreeList(v) ; |
| t := New() ; (* as it is a copy *) |
| t^ := v^ ; |
| CASE v^.type OF |
| |
| set : t^.setValue := DupRange(v^.setValue) | |
| constructor, |
| record : t^.fieldValues := DupFields(v^.fieldValues) | |
| array : t^.arrayValues := DupElements(v^.arrayValues) |
| |
| ELSE |
| END ; |
| Push(t) |
| END PushFrom ; |
| |
| |
| (* |
| PopInto - pops the top element from the stack and places it into, v. |
| *) |
| |
| PROCEDURE PopInto (v: PtrToValue) ; |
| VAR |
| t: PtrToValue ; |
| BEGIN |
| t := Pop() ; |
| v^ := t^ ; |
| CASE v^.type OF |
| |
| set : t^.setValue := NIL | |
| record, |
| constructor: t^.fieldValues := NIL | |
| array : t^.arrayValues := NIL | |
| none, |
| integer, |
| real, |
| complex : v^.numberValue := RememberConstant(FoldAndStrip(t^.numberValue)) |
| |
| ELSE |
| InternalError ('not expecting this value') |
| END ; |
| Dispose(t) |
| END PopInto ; |
| |
| |
| (* |
| PushCard - pushes a cardinal onto the stack. |
| *) |
| |
| PROCEDURE PushCard (c: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := New() ; |
| WITH v^ DO |
| type := integer ; |
| numberValue := BuildIntegerConstant(INTEGER(c)) ; |
| areAllConstants := TRUE ; |
| solved := TRUE |
| END ; |
| Push(v) |
| END PushCard ; |
| |
| |
| (* |
| PushInt - pushes an integer onto the stack. |
| *) |
| |
| PROCEDURE PushInt (i: INTEGER) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := New() ; |
| WITH v^ DO |
| type := integer ; |
| numberValue := BuildIntegerConstant(i) ; |
| areAllConstants := TRUE ; |
| solved := TRUE |
| END ; |
| Push(v) |
| END PushInt ; |
| |
| |
| (* |
| PushChar - pushes a char onto the stack. |
| *) |
| |
| PROCEDURE PushChar (c: CHAR) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := New() ; |
| WITH v^ DO |
| type := integer ; |
| numberValue := BuildIntegerConstant(ORD(c)) ; |
| areAllConstants := TRUE ; |
| solved := TRUE |
| END ; |
| Push(v) |
| END PushChar ; |
| |
| |
| (* |
| PopChar - pops a char from the stack. |
| *) |
| |
| PROCEDURE PopChar (tokenno: CARDINAL) : CHAR ; |
| VAR |
| v : PtrToValue ; |
| ch: CHAR ; |
| BEGIN |
| v := Pop () ; |
| ch := 0C ; |
| WITH v^ DO |
| IF type = integer |
| THEN |
| ch := VAL (CHAR, GetCstInteger (numberValue)) |
| ELSE |
| MetaErrorT0 (tokenno, '{%E}cannot convert constant to a CHAR') |
| END |
| END ; |
| Push (v) ; |
| RETURN ch |
| END PopChar ; |
| |
| |
| (* |
| IsReal - returns TRUE if a is a REAL number. |
| *) |
| |
| PROCEDURE IsReal (a: DynamicStrings.String) : BOOLEAN ; |
| BEGIN |
| RETURN( DynamicStrings.Index(a, '.', 0)#-1 ) |
| END IsReal ; |
| |
| |
| (* |
| PushString - pushes the numerical value of the string onto the stack. |
| *) |
| |
| PROCEDURE PushString (tokenno: CARDINAL; s: Name; issueError: BOOLEAN) ; |
| VAR |
| ch : CHAR ; |
| a, b : DynamicStrings.String ; |
| length : CARDINAL ; |
| location: location_t ; |
| BEGIN |
| a := DynamicStrings.InitStringCharStar (KeyToCharStar (s)) ; |
| b := NIL ; |
| length := DynamicStrings.Length (a) ; |
| IF length>0 |
| THEN |
| DEC (length) ; |
| ch := DynamicStrings.char (a, length) ; |
| location := TokenToLocation (tokenno) ; |
| CASE ch OF |
| |
| 'H': (* hexadecimal *) |
| b := DynamicStrings.Slice (a, 0, -1) ; |
| PushIntegerTree (BuildConstLiteralNumber (location, |
| DynamicStrings.string (b), |
| 16, issueError)) | |
| 'A': (* binary *) |
| b := DynamicStrings.Slice (a, 0, -1) ; |
| PushIntegerTree (BuildConstLiteralNumber (location, |
| DynamicStrings.string (b), |
| 2, issueError)) | |
| 'C', (* --fixme-- question: |
| should we type this as a char rather than an int? *) |
| 'B': (* octal *) |
| b := DynamicStrings.Slice (a, 0, -1) ; |
| PushIntegerTree (BuildConstLiteralNumber (location, |
| DynamicStrings.string (b), |
| 8, issueError)) |
| |
| ELSE |
| IF IsReal (a) |
| THEN |
| PushRealTree (RealToTree (KeyToCharStar (s))) |
| ELSE |
| PushIntegerTree (BuildConstLiteralNumber (location, KeyToCharStar (s), |
| 10, issueError)) |
| END |
| END |
| ELSE |
| InternalError ('expecting constant literal') |
| END ; |
| a := DynamicStrings.KillString (a) ; |
| b := DynamicStrings.KillString (b) |
| END PushString ; |
| |
| |
| (* |
| IsSolvedGCC - returns TRUE if the value, sym, is solved. |
| If TRUE then it also ensures this symbol is |
| entered into the double book keeping table |
| for GM2 <-> GCC. |
| *) |
| |
| PROCEDURE IsSolvedGCC (sym: CARDINAL) : BOOLEAN ; |
| BEGIN |
| IF IsValueSolved(sym) |
| THEN |
| IF NOT GccKnowsAbout(sym) |
| THEN |
| DeclareConstant(GetDeclaredMod(sym), sym) |
| END ; |
| RETURN( TRUE ) |
| ELSE |
| RETURN( FALSE ) |
| END |
| END IsSolvedGCC ; |
| |
| |
| (* |
| CoerseLongRealToCard - performs a coersion between a REAL to a CARDINAL |
| *) |
| |
| PROCEDURE CoerseLongRealToCard ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=real |
| THEN |
| numberValue := ConvertConstantAndCheck(location, GetIntegerType(), numberValue) ; |
| type := integer ; |
| areAllConstants := TRUE ; |
| solved := TRUE |
| ELSE |
| InternalError ('expecting a REAL number') |
| END |
| END ; |
| Push(v) |
| END CoerseLongRealToCard ; |
| |
| |
| (* |
| ConvertRealToInt - converts a REAL into an INTEGER |
| *) |
| |
| PROCEDURE ConvertRealToInt ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=real |
| THEN |
| numberValue := ConvertConstantAndCheck(location, GetIntegerType(), numberValue) ; |
| type := integer ; |
| areAllConstants := TRUE ; |
| solved := TRUE |
| ELSE |
| InternalError ('expecting a REAL number') |
| END |
| END ; |
| Push(v) |
| END ConvertRealToInt ; |
| |
| |
| (* |
| ConvertIntToReal - converts a INTEGER into a LONGREAL |
| *) |
| |
| PROCEDURE ConvertIntToReal ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=integer |
| THEN |
| numberValue := ConvertConstantAndCheck(location, GetLongRealType(), numberValue) ; |
| type := real ; |
| areAllConstants := TRUE ; |
| solved := TRUE |
| ELSE |
| InternalError ('expecting an INTEGER number') |
| END |
| END ; |
| Push(v) |
| END ConvertIntToReal ; |
| |
| |
| (* |
| ConvertToInt - converts the value into an INTEGER. This should be used |
| if we are computing the number of elements in a char set to |
| avoid an overflow. |
| *) |
| |
| PROCEDURE ConvertToInt ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| IF type=integer |
| THEN |
| numberValue := ConvertConstantAndCheck(location, GetIntegerType(), numberValue) ; |
| solved := TRUE ; |
| areAllConstants := TRUE |
| ELSE |
| InternalError ('expecting an INTEGER number') |
| END |
| END ; |
| Push(v) |
| END ConvertToInt ; |
| |
| |
| (* |
| ConvertToType - converts the top of stack to type, t. |
| *) |
| |
| PROCEDURE ConvertToType (t: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| IF t#NulSym |
| THEN |
| WITH v^ DO |
| IF type=integer |
| THEN |
| numberValue := ConvertConstantAndCheck(location, Mod2Gcc(t), numberValue) ; |
| solved := TRUE ; |
| areAllConstants := TRUE |
| ELSE |
| InternalError ('expecting an INTEGER number') |
| END |
| END |
| END ; |
| Push(v) |
| END ConvertToType ; |
| |
| |
| |
| (* |
| IsSolved - returns true if the memory cell indicated by v |
| has a known value. |
| *) |
| |
| PROCEDURE IsSolved (v: PtrToValue) : BOOLEAN ; |
| BEGIN |
| IF v=NIL |
| THEN |
| InternalError ('uninitialized value') |
| ELSE |
| RETURN( v^.solved ) |
| END |
| END IsSolved ; |
| |
| |
| (* |
| IsValueConst - returns true if the memory cell indicated by v |
| is only defined by constants. For example |
| no variables are used in the constructor. |
| *) |
| |
| PROCEDURE IsValueConst (v: PtrToValue) : BOOLEAN ; |
| BEGIN |
| IF v=NIL |
| THEN |
| InternalError ('uninitialized value') |
| ELSE |
| RETURN( v^.areAllConstants ) |
| END |
| END IsValueConst ; |
| |
| |
| (* |
| EitherReal - returns TRUE if either, Op1, or, Op2, are Real. |
| *) |
| |
| PROCEDURE EitherReal (Op1, Op2: PtrToValue) : BOOLEAN ; |
| BEGIN |
| RETURN( (Op1^.type=real) OR (Op2^.type=real) ) |
| END EitherReal ; |
| |
| |
| (* |
| EitherComplex - returns TRUE if either, Op1, or, Op2, are Real. |
| *) |
| |
| PROCEDURE EitherComplex (Op1, Op2: PtrToValue) : BOOLEAN ; |
| BEGIN |
| RETURN( (Op1^.type=complex) OR (Op2^.type=complex) ) |
| END EitherComplex ; |
| |
| |
| (* |
| Add - adds the top two elements on the stack. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | <- Ptr |
| |------------| +------------+ |
| | Op2 | | Op2 + Op1 | |
| |------------| |------------| |
| *) |
| |
| PROCEDURE Addn ; |
| VAR |
| Temp, |
| Op1, Op2: PtrToValue ; |
| BEGIN |
| Op1 := Pop() ; |
| Op2 := Pop() ; |
| IF EitherReal(Op1, Op2) |
| THEN |
| RealAdd(Op1, Op2) |
| ELSIF EitherComplex(Op1, Op2) |
| THEN |
| ComplexAdd(Op1, Op2) |
| ELSE |
| Temp := New() ; (* as it is a temp *) |
| WITH Temp^ DO |
| location := Op1^.location ; |
| type := integer ; |
| numberValue := BuildAdd(location, Op1^.numberValue, Op2^.numberValue, FALSE) ; |
| solved := TRUE |
| END ; |
| Push(Temp) |
| END ; |
| Dispose(Op1) ; |
| Dispose(Op2) |
| END Addn ; |
| |
| |
| (* |
| RealAdd - adds two numbers. One of which is a Real. |
| *) |
| |
| PROCEDURE RealAdd (Op1, Op2: PtrToValue) ; |
| VAR |
| Temp: PtrToValue ; |
| BEGIN |
| IF Op1^.type=integer |
| THEN |
| Push(Op1) ; |
| ConvertIntToReal ; |
| Op1 := Pop() |
| END ; |
| IF Op2^.type=integer |
| THEN |
| Push(Op2) ; |
| ConvertIntToReal ; |
| Op2 := Pop() |
| END ; |
| Temp := New() ; |
| WITH Temp^ DO |
| location := Op1^.location ; |
| numberValue := BuildAdd(location, Op1^.numberValue, Op2^.numberValue, FALSE) ; |
| type := real ; |
| solved := TRUE |
| END ; |
| Push(Temp) |
| END RealAdd ; |
| |
| |
| (* |
| ComplexAdd - adds two complex numbers. |
| *) |
| |
| PROCEDURE ComplexAdd (Op1, Op2: PtrToValue) ; |
| VAR |
| Temp: PtrToValue ; |
| BEGIN |
| IF (Op1^.type=complex) AND (Op2^.type=complex) |
| THEN |
| Temp := New() ; |
| WITH Temp^ DO |
| location := Op1^.location ; |
| numberValue := BuildAdd(location, Op1^.numberValue, Op2^.numberValue, FALSE) ; |
| type := complex ; |
| solved := TRUE |
| END ; |
| Push(Temp) |
| ELSE |
| InternalError ('expecting both operands to be of type COMPLEX') |
| END |
| END ComplexAdd ; |
| |
| |
| (* |
| Sub - subtracts the top two elements on the stack. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | <- Ptr |
| |------------| +------------+ |
| | Op2 | | Op2 - Op1 | |
| |------------| |------------| |
| *) |
| |
| PROCEDURE Sub ; |
| VAR |
| Temp, |
| Op1, Op2: PtrToValue ; |
| BEGIN |
| Op1 := Pop() ; |
| Op2 := Pop() ; |
| IF EitherReal(Op1, Op2) |
| THEN |
| RealSub(Op1, Op2) |
| ELSIF EitherComplex(Op1, Op2) |
| THEN |
| ComplexSub(Op1, Op2) |
| ELSE |
| Temp := New() ; (* as it is a temp *) |
| WITH Temp^ DO |
| location := Op1^.location ; |
| type := integer ; |
| numberValue := BuildSub(location, Op2^.numberValue, Op1^.numberValue, TRUE) ; |
| solved := TRUE |
| END ; |
| Push(Temp) |
| END ; |
| Dispose(Op1) ; |
| Dispose(Op2) |
| END Sub ; |
| |
| |
| (* |
| RealSub - subtracts two numbers. One of which is a Real. |
| *) |
| |
| PROCEDURE RealSub (Op1, Op2: PtrToValue) ; |
| VAR |
| Temp: PtrToValue ; |
| BEGIN |
| IF Op1^.type=integer |
| THEN |
| Push(Op1) ; |
| ConvertIntToReal ; |
| Op1 := Pop() |
| END ; |
| IF Op2^.type=integer |
| THEN |
| Push(Op2) ; |
| ConvertIntToReal ; |
| Op2 := Pop() |
| END ; |
| Temp := New() ; |
| WITH Temp^ DO |
| location := Op1^.location ; |
| numberValue := BuildSub(location, Op2^.numberValue, Op1^.numberValue, FALSE) ; |
| type := real ; |
| solved := TRUE |
| END ; |
| Push(Temp) |
| END RealSub ; |
| |
| |
| (* |
| ComplexSub - subtracts two complex numbers. |
| *) |
| |
| PROCEDURE ComplexSub (Op1, Op2: PtrToValue) ; |
| VAR |
| Temp: PtrToValue ; |
| BEGIN |
| IF (Op1^.type=complex) AND (Op2^.type=complex) |
| THEN |
| Temp := New() ; |
| WITH Temp^ DO |
| location := Op1^.location ; |
| numberValue := BuildSub(location, Op2^.numberValue, Op1^.numberValue, FALSE) ; |
| type := complex ; |
| solved := TRUE |
| END ; |
| Push(Temp) |
| ELSE |
| InternalError ('expecting both operands to be of type COMPLEX') |
| END |
| END ComplexSub ; |
| |
| |
| (* |
| Mult - multiplies the top two elements on the stack. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | <- Ptr |
| |------------| +------------+ |
| | Op2 | | Op2 * Op1 | |
| |------------| |------------| |
| *) |
| |
| PROCEDURE Multn ; |
| VAR |
| Temp, |
| Op1, Op2: PtrToValue ; |
| BEGIN |
| Op1 := Pop() ; |
| Op2 := Pop() ; |
| IF EitherReal(Op1, Op2) |
| THEN |
| RealMult(Op1, Op2) |
| ELSIF EitherComplex(Op1, Op2) |
| THEN |
| ComplexMult(Op1, Op2) |
| ELSE |
| Temp := New() ; (* as it is a temp *) |
| WITH Temp^ DO |
| location := Op1^.location ; |
| type := integer ; |
| numberValue := BuildMult(location, Op2^.numberValue, Op1^.numberValue, FALSE) ; |
| solved := TRUE |
| END ; |
| Push(Temp) |
| END ; |
| Dispose(Op1) ; |
| Dispose(Op2) |
| END Multn ; |
| |
| |
| (* |
| RealMult - multiplies two numbers. One of which is a Real. |
| *) |
| |
| PROCEDURE RealMult (Op1, Op2: PtrToValue) ; |
| VAR |
| Temp: PtrToValue ; |
| BEGIN |
| IF Op1^.type=integer |
| THEN |
| Push(Op1) ; |
| ConvertIntToReal ; |
| Op1 := Pop() |
| END ; |
| IF Op2^.type=integer |
| THEN |
| Push(Op2) ; |
| ConvertIntToReal ; |
| Op2 := Pop() |
| END ; |
| Temp := New() ; (* as it is a temp *) |
| WITH Temp^ DO |
| location := Op1^.location ; |
| numberValue := BuildMult(location, Op2^.numberValue, Op1^.numberValue, FALSE) ; |
| type := real ; |
| solved := TRUE |
| END ; |
| Push(Temp) |
| END RealMult ; |
| |
| |
| (* |
| ComplexMult - multiplies two complex numbers. |
| *) |
| |
| PROCEDURE ComplexMult (Op1, Op2: PtrToValue) ; |
| VAR |
| Temp: PtrToValue ; |
| BEGIN |
| IF (Op1^.type=complex) AND (Op2^.type=complex) |
| THEN |
| Temp := New() ; |
| WITH Temp^ DO |
| location := Op1^.location ; |
| numberValue := BuildMult(location, Op2^.numberValue, Op1^.numberValue, FALSE) ; |
| type := complex ; |
| solved := TRUE |
| END ; |
| Push(Temp) |
| ELSE |
| InternalError ('expecting both operands to be of type COMPLEX') |
| END |
| END ComplexMult ; |
| |
| |
| (* |
| DivTrunc - divides the top two elements on the stack. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | <- Ptr |
| |------------| +--------------+ |
| | Op2 | | Op2 DIV Op1 | |
| |------------| |--------------| |
| *) |
| |
| PROCEDURE DivTrunc ; |
| VAR |
| Temp, |
| Op1, Op2: PtrToValue ; |
| BEGIN |
| Op1 := Pop() ; |
| Op2 := Pop() ; |
| IF EitherReal(Op1, Op2) |
| THEN |
| RealDiv(Op1, Op2) |
| ELSIF EitherComplex(Op1, Op2) |
| THEN |
| ComplexDiv(Op1, Op2) |
| ELSE |
| Temp := New() ; (* as it is a temp *) |
| WITH Temp^ DO |
| location := Op1^.location ; |
| type := integer ; |
| numberValue := BuildDivTrunc(location, Op2^.numberValue, Op1^.numberValue, FALSE) ; |
| solved := TRUE |
| END ; |
| Push(Temp) |
| END ; |
| Dispose(Op1) ; |
| Dispose(Op2) |
| END DivTrunc ; |
| |
| |
| (* |
| DivFloor - divides the top two elements on the stack. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | <- Ptr |
| |------------| +--------------+ |
| | Op2 | | Op2 DIV Op1 | |
| |------------| |--------------| |
| *) |
| |
| PROCEDURE DivFloor ; |
| VAR |
| Temp, |
| Op1, Op2: PtrToValue ; |
| BEGIN |
| Op1 := Pop() ; |
| Op2 := Pop() ; |
| IF EitherReal(Op1, Op2) |
| THEN |
| RealDiv(Op1, Op2) |
| ELSIF EitherComplex(Op1, Op2) |
| THEN |
| ComplexDiv(Op1, Op2) |
| ELSE |
| Temp := New() ; (* as it is a temp *) |
| WITH Temp^ DO |
| location := Op1^.location ; |
| type := integer ; |
| numberValue := BuildDivFloor(location, Op2^.numberValue, Op1^.numberValue, FALSE) ; |
| solved := TRUE |
| END ; |
| Push(Temp) |
| END ; |
| Dispose(Op1) ; |
| Dispose(Op2) |
| END DivFloor ; |
| |
| |
| (* |
| RealDiv - divides two numbers. One of which is a Real. |
| *) |
| |
| PROCEDURE RealDiv (Op1, Op2: PtrToValue) ; |
| VAR |
| Temp: PtrToValue ; |
| BEGIN |
| IF Op1^.type=integer |
| THEN |
| Push(Op1) ; |
| ConvertIntToReal ; |
| Op1 := Pop() |
| END ; |
| IF Op2^.type=integer |
| THEN |
| Push(Op2) ; |
| ConvertIntToReal ; |
| Op2 := Pop() |
| END ; |
| Temp := New() ; (* as it is a temp *) |
| WITH Temp^ DO |
| location := Op1^.location ; |
| numberValue := BuildDivTrunc(location, Op2^.numberValue, Op1^.numberValue, FALSE) ; |
| type := real ; |
| solved := TRUE |
| END ; |
| Push(Temp) |
| END RealDiv ; |
| |
| |
| (* |
| ComplexDiv - divides two complex numbers. |
| *) |
| |
| PROCEDURE ComplexDiv (Op1, Op2: PtrToValue) ; |
| VAR |
| Temp: PtrToValue ; |
| BEGIN |
| IF (Op1^.type=complex) AND (Op2^.type=complex) |
| THEN |
| Temp := New() ; |
| WITH Temp^ DO |
| location := Op1^.location ; |
| numberValue := BuildDivTrunc(location, Op2^.numberValue, Op1^.numberValue, FALSE) ; |
| type := complex ; |
| solved := TRUE |
| END ; |
| Push(Temp) |
| ELSE |
| InternalError ('expecting both operands to be of type COMPLEX') |
| END |
| END ComplexDiv ; |
| |
| |
| (* |
| ModFloor - modulus of the top two elements on the stack. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | <- Ptr |
| |------------| +--------------+ |
| | Op2 | | Op2 MOD Op1 | |
| |------------| |--------------| |
| *) |
| |
| PROCEDURE ModFloor ; |
| VAR |
| Temp, |
| Op1, Op2: PtrToValue ; |
| BEGIN |
| Op1 := Pop() ; |
| Op2 := Pop() ; |
| IF EitherReal(Op1, Op2) |
| THEN |
| MetaError0 ('cannot perform {%EkMOD} on REAL types') |
| ELSIF EitherComplex(Op1, Op2) |
| THEN |
| MetaError0 ('cannot perform {%EkMOD} on COMPLEX types') |
| ELSE |
| Temp := New() ; (* as it is a temp *) |
| WITH Temp^ DO |
| location := Op1^.location ; |
| type := integer ; |
| numberValue := BuildModFloor(location, Op2^.numberValue, Op1^.numberValue, FALSE) ; |
| solved := TRUE |
| END ; |
| Push(Temp) |
| END ; |
| Dispose(Op1) ; |
| Dispose(Op2) |
| END ModFloor ; |
| |
| |
| (* |
| ModTrunc - modulus of the top two elements on the stack. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | <- Ptr |
| |------------| +--------------+ |
| | Op2 | | Op2 MOD Op1 | |
| |------------| |--------------| |
| *) |
| |
| PROCEDURE ModTrunc ; |
| VAR |
| Temp, |
| Op1, Op2: PtrToValue ; |
| BEGIN |
| Op1 := Pop() ; |
| Op2 := Pop() ; |
| IF EitherReal(Op1, Op2) |
| THEN |
| MetaError0 ('cannot perform {%EkMOD} on REAL types') |
| ELSIF EitherComplex(Op1, Op2) |
| THEN |
| MetaError0 ('cannot perform {%EkMOD} on COMPLEX types') |
| ELSE |
| Temp := New() ; (* as it is a temp *) |
| WITH Temp^ DO |
| location := Op1^.location ; |
| type := integer ; |
| numberValue := BuildModTrunc(location, Op2^.numberValue, Op1^.numberValue, FALSE) ; |
| solved := TRUE |
| END ; |
| Push(Temp) |
| END ; |
| Dispose(Op1) ; |
| Dispose(Op2) |
| END ModTrunc ; |
| |
| |
| (* |
| AreSetsEqual - returns TRUE if sets, op1, and, op2, contain the same |
| members. |
| *) |
| |
| PROCEDURE AreSetsEqual (tokenno: CARDINAL; op1, op2: PtrToValue) : BOOLEAN ; |
| VAR |
| low1, low2, |
| high1, high2: CARDINAL ; |
| i : CARDINAL ; |
| BEGIN |
| i := 1 ; |
| Eval(tokenno, op1) ; |
| Eval(tokenno, op2) ; |
| IF NOT (op1^.solved AND op2^.solved) |
| THEN |
| InternalError ('can only compare set values when they are known') |
| END ; |
| LOOP |
| IF GetRange(op1, i, low1, high1) |
| THEN |
| IF GetRange(op2, i, low2, high2) |
| THEN |
| PushValue(low1) ; |
| PushValue(low2) ; |
| IF NotEqu(tokenno) |
| THEN |
| RETURN( FALSE ) |
| END ; |
| PushValue(high1) ; |
| PushValue(high2) ; |
| IF NotEqu(tokenno) |
| THEN |
| RETURN( FALSE ) |
| END ; |
| INC(i) |
| ELSE |
| (* op2 is out of ranges, but op1 still has >= 1 range left *) |
| RETURN( FALSE ) |
| END |
| ELSE |
| IF GetRange(op2, i, low2, high2) |
| THEN |
| (* op1 is out of ranges, but op2 still has >= 1 range left *) |
| RETURN( FALSE ) |
| ELSE |
| (* both out of ranges and they were the same *) |
| RETURN( TRUE ) |
| END |
| END |
| END |
| END AreSetsEqual ; |
| |
| |
| (* |
| Equ - returns true if the top two elements on the stack |
| are identical. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | |
| |------------| |
| | Op2 | |
| |------------| Empty |
| |
| RETURN( Op2 = Op1 ) |
| *) |
| |
| PROCEDURE Equ (tokenno: CARDINAL) : BOOLEAN ; |
| VAR |
| Op1, Op2: PtrToValue ; |
| result : BOOLEAN ; |
| BEGIN |
| Op1 := Pop() ; |
| Op2 := Pop() ; |
| IF (Op1^.type=set) AND (Op2^.type=set) |
| THEN |
| result := AreSetsEqual(tokenno, Op1, Op2) |
| ELSIF (Op1^.type=set) OR (Op2^.type=set) |
| THEN |
| MetaErrorT0 (tokenno, 'cannot perform a comparison between a number and a set') ; |
| result := FALSE |
| ELSE |
| IF Op1^.type#Op2^.type |
| THEN |
| MetaErrorT0 (tokenno, 'cannot perform a comparison between a different type constants') ; |
| result := FALSE |
| ELSIF (Op1^.type=complex) OR (Op1^.type=real) |
| THEN |
| result := AreRealOrComplexConstantsEqual(Op1^.numberValue, Op2^.numberValue) |
| ELSE |
| result := AreConstantsEqual(Op1^.numberValue, Op2^.numberValue) |
| END |
| END ; |
| Dispose(Op1) ; |
| Dispose(Op2) ; |
| RETURN( result ) |
| END Equ ; |
| |
| |
| (* |
| NotEqu - returns true if the top two elements on the stack |
| are not identical. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | |
| |------------| |
| | Op2 | |
| |------------| Empty |
| |
| RETURN( Op2 # Op1 ) |
| *) |
| |
| PROCEDURE NotEqu (tokenno: CARDINAL) : BOOLEAN ; |
| BEGIN |
| RETURN( NOT Equ(tokenno) ) |
| END NotEqu ; |
| |
| |
| (* |
| Less - returns true if Op2 < Op1 |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | |
| |------------| |
| | Op2 | |
| |------------| Empty |
| |
| RETURN( Op2 < Op1 ) |
| *) |
| |
| PROCEDURE Less (tokenno: CARDINAL) : BOOLEAN ; |
| VAR |
| v1, v2: PtrToValue ; |
| result: BOOLEAN ; |
| res : INTEGER ; |
| BEGIN |
| v1 := Pop () ; |
| v2 := Pop () ; |
| IF (v1^.type = set) AND (v2^.type = set) |
| THEN |
| result := NOT IsSuperset (tokenno, v2, v1) |
| ELSIF (v1^.type = set) OR (v2^.type = set) |
| THEN |
| MetaErrorT0 (tokenno, 'cannot perform a comparison between a number and a set') ; |
| result := FALSE |
| ELSE |
| res := CompareTrees (v2^.numberValue, v1^.numberValue) ; |
| IF res = -1 |
| THEN |
| result := TRUE |
| ELSE |
| result := FALSE |
| END ; |
| (* result := (CompareTrees(v2^.numberValue, v1^.numberValue)=-1) *) |
| END ; |
| Dispose (v1) ; |
| Dispose (v2) ; |
| RETURN result |
| END Less ; |
| |
| |
| (* |
| Gre - returns true if Op2 > Op1 |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | |
| |------------| |
| | Op2 | |
| |------------| Empty |
| |
| RETURN( Op2 > Op1 ) |
| *) |
| |
| PROCEDURE Gre (tokenno: CARDINAL) : BOOLEAN ; |
| VAR |
| v1, v2: PtrToValue ; |
| result: BOOLEAN ; |
| BEGIN |
| v1 := Pop() ; |
| v2 := Pop() ; |
| IF (v1^.type=set) AND (v2^.type=set) |
| THEN |
| result := NOT IsSubset(tokenno, v2, v1) |
| ELSIF (v1^.type=set) OR (v2^.type=set) |
| THEN |
| MetaErrorT0 (tokenno, 'cannot perform a comparison between a number and a set') ; |
| FlushErrors ; |
| result := FALSE |
| ELSE |
| result := (CompareTrees(v2^.numberValue, v1^.numberValue)=1) |
| END ; |
| Dispose(v1) ; |
| Dispose(v2) ; |
| RETURN( result ) |
| END Gre ; |
| |
| |
| (* |
| IsSubset - returns TRUE if the set as defined by, s1, is a subset of set, s2. |
| *) |
| |
| PROCEDURE IsSubset (tokenno: CARDINAL; s1, s2: PtrToValue) : BOOLEAN ; |
| BEGIN |
| Push(s1) ; |
| Push(s2) ; |
| SetAnd(tokenno) ; |
| Push(s1) ; |
| RETURN( Equ(tokenno) ) |
| END IsSubset ; |
| |
| |
| (* |
| LessEqu - returns true if Op2<Op1 |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | |
| |------------| |
| | Op2 | |
| |------------| Empty |
| |
| RETURN( Op2 <= Op1 ) |
| *) |
| |
| PROCEDURE LessEqu (tokenno: CARDINAL) : BOOLEAN ; |
| VAR |
| v1, v2: PtrToValue ; |
| result: BOOLEAN ; |
| BEGIN |
| v1 := Pop() ; |
| v2 := Pop() ; |
| IF (v1^.type=set) AND (v2^.type=set) |
| THEN |
| result := IsSubset(tokenno, v2, v1) |
| ELSIF (v1^.type=set) OR (v2^.type=set) |
| THEN |
| MetaErrorT0 (tokenno, 'cannot perform a comparison between a number and a set') ; |
| FlushErrors ; |
| result := FALSE |
| ELSE |
| result := (CompareTrees(v2^.numberValue, v1^.numberValue)<=0) |
| END ; |
| Dispose(v1) ; |
| Dispose(v2) ; |
| RETURN( result ) |
| END LessEqu ; |
| |
| |
| (* |
| IsSuperset - returns TRUE if the set as defined by, s1, is a superset of set, s2. |
| *) |
| |
| PROCEDURE IsSuperset (tokenno: CARDINAL; s1, s2: PtrToValue) : BOOLEAN ; |
| BEGIN |
| PushFrom(s1) ; |
| PushFrom(s2) ; |
| SetAnd(tokenno) ; |
| PushFrom(s2) ; |
| RETURN( Equ(tokenno) ) |
| END IsSuperset ; |
| |
| |
| (* |
| GreEqu - returns true if Op2 >= Op1 |
| are not identical. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | |
| |------------| |
| | Op2 | |
| |------------| Empty |
| |
| RETURN( Op2 >= Op1 ) |
| *) |
| |
| PROCEDURE GreEqu (tokenno: CARDINAL) : BOOLEAN ; |
| VAR |
| v1, v2: PtrToValue ; |
| result: BOOLEAN ; |
| BEGIN |
| v1 := Pop() ; |
| v2 := Pop() ; |
| IF (v1^.type=set) AND (v2^.type=set) |
| THEN |
| result := IsSuperset(tokenno, v2, v1) |
| ELSIF (v1^.type=set) OR (v2^.type=set) |
| THEN |
| MetaErrorT0 (tokenno, 'cannot perform a comparison between a number and a set') ; |
| FlushErrors ; |
| result := FALSE |
| ELSE |
| result := (CompareTrees(v2^.numberValue, v1^.numberValue)>=0) |
| END ; |
| Dispose(v1) ; |
| Dispose(v2) ; |
| RETURN( result ) |
| END GreEqu ; |
| |
| |
| (* |
| IsNulSet - returns TRUE if the top element is the nul set constant, {}. |
| *) |
| |
| PROCEDURE IsNulSet () : BOOLEAN ; |
| VAR |
| v: PtrToValue ; |
| r: BOOLEAN ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| r := (type=set) AND (setValue=NIL) |
| END ; |
| Push(v) ; |
| RETURN( r ) |
| END IsNulSet ; |
| |
| |
| (* |
| IsGenericNulSet - returns TRUE if the top element is the generic nul set constant, {}. |
| *) |
| |
| PROCEDURE IsGenericNulSet () : BOOLEAN ; |
| VAR |
| v: PtrToValue ; |
| r: BOOLEAN ; |
| BEGIN |
| v := Pop() ; |
| WITH v^ DO |
| r := (type=set) AND (setValue=NIL) AND (constructorType=NulSym) |
| END ; |
| Push(v) ; |
| RETURN( r ) |
| END IsGenericNulSet ; |
| |
| |
| (* |
| PushNulSet - pushes an empty set {} onto the ALU stack. The subrange type used |
| to construct the set is defined by, constructorType. |
| If this is NulSym then |
| the set is generic and compatible with all sets. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| <- Ptr |
| +------------+ |
| | {} | |
| Ptr -> |------------| |
| |
| *) |
| |
| PROCEDURE PushNulSet (settype: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := InitValue() ; |
| WITH v^ DO |
| type := set ; |
| constructorType := settype ; |
| areAllConstants := TRUE ; |
| solved := CompletelyResolved(settype) ; |
| setValue := NIL ; |
| next := NIL ; |
| END ; |
| Push(v) |
| END PushNulSet ; |
| |
| |
| (* |
| PushEmptyConstructor - pushes an empty constructor {} onto the ALU stack. |
| This is expected to be filled in by subsequent |
| calls to AddElements, AddRange or AddField. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| <- Ptr |
| +------------+ |
| | {} | |
| Ptr -> |------------| |
| |
| *) |
| |
| PROCEDURE PushEmptyConstructor (constype: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := InitValue() ; |
| WITH v^ DO |
| type := constructor ; |
| constructorType := constype ; |
| areAllConstants := TRUE ; |
| solved := CompletelyResolved(constype) ; |
| fieldValues := NIL ; |
| next := NIL ; |
| END ; |
| Push(v) |
| END PushEmptyConstructor ; |
| |
| |
| (* |
| PushEmptyArray - pushes an empty array {} onto the ALU stack. |
| This is expected to be filled in by subsequent |
| calls to AddElements. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| <- Ptr |
| +------------+ |
| | {} | |
| Ptr -> |------------| |
| |
| *) |
| |
| PROCEDURE PushEmptyArray (arraytype: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := InitValue() ; |
| WITH v^ DO |
| type := array ; |
| constructorType := arraytype ; |
| areAllConstants := TRUE ; |
| solved := CompletelyResolved(arraytype) ; |
| arrayValues := NIL ; |
| next := NIL ; |
| END ; |
| Push(v) |
| END PushEmptyArray ; |
| |
| |
| (* |
| PushEmptyRecord - pushes an empty record {} onto the ALU stack. |
| This is expected to be filled in by subsequent |
| calls to AddField. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| <- Ptr |
| +------------+ |
| | {} | |
| Ptr -> |------------| |
| |
| *) |
| |
| PROCEDURE PushEmptyRecord (recordtype: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := InitValue() ; |
| WITH v^ DO |
| type := record ; |
| constructorType := recordtype ; |
| areAllConstants := TRUE ; |
| solved := CompletelyResolved(recordtype) ; |
| arrayValues := NIL ; |
| next := NIL ; |
| END ; |
| Push(v) |
| END PushEmptyRecord ; |
| |
| |
| (* |
| AddElements - adds the elements, el BY, n, to the array constant. |
| |
| Ptr -> |
| <- Ptr |
| +------------+ +------------+ |
| | Array | | Array | |
| |------------| |------------| |
| |
| *) |
| |
| PROCEDURE AddElements (tokenno: CARDINAL; el, n: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| e: listOfElements ; |
| BEGIN |
| v := Pop() ; |
| v := CoerseTo(tokenno, array, v) ; |
| IF v^.type=array |
| THEN |
| NewElement(e) ; |
| WITH e^ DO |
| element := el ; |
| by := n ; |
| next := NIL |
| END ; |
| AddElementToEnd(v, e) ; |
| WITH v^ DO |
| solved := solved AND IsSolvedGCC(el) AND IsSolvedGCC(n) |
| END |
| ELSE |
| InternalError ('expecting array type') |
| END ; |
| Push(v) |
| END AddElements ; |
| |
| |
| (* |
| AddElement - |
| |
| PROCEDURE AddElement (v: listOfElements; |
| e, b: CARDINAL) : listOfElements ; |
| VAR |
| el: listOfElements ; |
| BEGIN |
| NEW(el) ; |
| IF el=NIL |
| THEN |
| InternalError ('out of memory') |
| END ; |
| (* held in reverse order here *) |
| WITH el^ DO |
| element := e ; |
| by := b ; |
| next := v^.next |
| END ; |
| v^.next := el ; |
| RETURN( v ) |
| END AddElement ; |
| *) |
| |
| |
| (* |
| cellTypeString - returns a string corresponding to, s. |
| *) |
| |
| PROCEDURE cellTypeString (s: cellType) : String ; |
| BEGIN |
| CASE s OF |
| |
| none : RETURN( InitString('none') ) | |
| integer : RETURN( InitString('integer') ) | |
| real : RETURN( InitString('real') ) | |
| complex : RETURN( InitString('complex') ) | |
| set : RETURN( InitString('set') ) | |
| constructor: RETURN( InitString('constructor') ) | |
| array : RETURN( InitString('array') ) | |
| record : RETURN( InitString('record') ) |
| |
| ELSE |
| InternalError ('unexpected value of s') |
| END ; |
| RETURN( NIL ) |
| END cellTypeString ; |
| |
| |
| (* |
| ToSetValue - converts a list of fields into a list of ranges. |
| In effect it turns a generic constructor into |
| a set type. |
| *) |
| |
| PROCEDURE ToSetValue (f: listOfFields) : listOfRange ; |
| VAR |
| g : listOfFields ; |
| r, s: listOfRange ; |
| BEGIN |
| g := f ; |
| r := NIL ; |
| WHILE f#NIL DO |
| NewRange(s) ; |
| WITH s^ DO |
| low := f^.field ; |
| high := low ; |
| next := r |
| END ; |
| IF r=NIL |
| THEN |
| r := s |
| END ; |
| f := f^.next |
| END ; |
| DisposeFields(g) ; |
| RETURN( r ) |
| END ToSetValue ; |
| |
| |
| (* |
| ToArrayValue - converts a list of fields into an array initialiser. |
| In effect it turns a generic constructor into |
| an array type. |
| *) |
| |
| PROCEDURE ToArrayValue (tok: CARDINAL; f: listOfFields) : listOfElements ; |
| VAR |
| g : listOfFields ; |
| r, s: listOfElements ; |
| BEGIN |
| g := f ; |
| r := NIL ; |
| WHILE f#NIL DO |
| NewElement(s) ; |
| WITH s^ DO |
| element := f^.field ; |
| by := MakeConstLit (tok, MakeKey('1'), ZType) ; |
| next := r |
| END ; |
| IF r=NIL |
| THEN |
| r := s |
| END ; |
| f := f^.next |
| END ; |
| DisposeFields(g) ; |
| RETURN( r ) |
| END ToArrayValue ; |
| |
| |
| (* |
| ChangeToConstructor - change the top of stack value to a constructor, type. |
| (Constructor, Set, Array or Record). |
| *) |
| |
| PROCEDURE ChangeToConstructor (tokenno: CARDINAL; constype: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| IF IsValueTypeConstructor() OR IsValueTypeSet() OR |
| IsValueTypeArray() OR IsValueTypeRecord() |
| THEN |
| RETURN |
| ELSIF IsValueTypeNone() |
| THEN |
| v := Pop() ; |
| WITH v^ DO |
| type := constructor ; |
| constructorType := constype ; |
| solved := CompletelyResolved(constype) ; |
| fieldValues := NIL ; |
| next := NIL ; |
| END ; |
| IF IsSet(SkipType(constype)) |
| THEN |
| v := CoerseTo(tokenno, set, v) |
| ELSIF IsRecord(SkipType(constype)) |
| THEN |
| v := CoerseTo(tokenno, record, v) |
| ELSIF IsArray(SkipType(constype)) |
| THEN |
| v := CoerseTo(tokenno, array, v) |
| END ; |
| Push(v) |
| ELSE |
| InternalError('cannot change constant to a constructor type') |
| END |
| END ChangeToConstructor ; |
| |
| |
| (* |
| CoerseTo - attempts to coerses a cellType, v, into, type, t. |
| Normally this will be a generic constructors converting |
| into set or array. |
| *) |
| |
| PROCEDURE CoerseTo (tokenno: CARDINAL; |
| t: cellType; v: PtrToValue) : PtrToValue ; |
| VAR |
| s1, s2, s3: DynamicStrings.String ; |
| BEGIN |
| WITH v^ DO |
| IF t=type |
| THEN |
| RETURN( v ) |
| ELSIF (type=constructor) AND (t=set) |
| THEN |
| type := set ; |
| setValue := ToSetValue(fieldValues) ; |
| RETURN( v ) |
| ELSIF (type=constructor) AND (t=array) |
| THEN |
| type := array ; |
| arrayValues := ToArrayValue (tokenno, fieldValues) ; |
| RETURN( v ) |
| ELSIF (type=constructor) AND (t=record) |
| THEN |
| (* nothing to do other than change tag *) |
| type := record ; |
| RETURN( v ) |
| ELSE |
| s1 := cellTypeString (t) ; |
| s2 := cellTypeString (type) ; |
| s3 := ConCat(InitString('cannot mix construction of a '), |
| Mark(ConCat(Mark(s1), |
| Mark(ConCat(InitString(' with a '), |
| (Mark(s2))))))) ; |
| MetaErrorStringT0 (tokenno, s3) ; |
| RETURN( v ) |
| END |
| END |
| END CoerseTo ; |
| |
| |
| (* |
| SetNegate - negates the top set on the stack. |
| |
| Ptr -> <- Ptr |
| +-----------+ +------------+ |
| | Set | | Set | |
| |-----------| |------------| |
| *) |
| |
| PROCEDURE SetNegate (tokenno: CARDINAL) ; |
| VAR |
| min, |
| max : CARDINAL ; |
| r, s: listOfRange ; |
| v : PtrToValue ; |
| i : CARDINAL ; |
| BEGIN |
| v := Pop() ; |
| Eval(tokenno, v) ; |
| IF v^.constructorType=NulSym |
| THEN |
| MetaError0 ('cannot negate a generic set, set should be prefixed by a simple type') |
| END ; |
| r := NIL ; |
| min := GetTypeMin(GetType(v^.constructorType)) ; |
| max := GetTypeMax(GetType(v^.constructorType)) ; |
| i := min ; |
| s := v^.setValue ; |
| IF Debugging |
| THEN |
| printf0('attempting to negate set\n') ; |
| DisplayElements(s) |
| END ; |
| WHILE s#NIL DO |
| PushValue(s^.low) ; |
| PushValue(min) ; |
| IF Gre(tokenno) |
| THEN |
| PushValue(i) ; |
| PushValue(max) ; |
| IF LessEqu(tokenno) |
| THEN |
| r := AddRange(r, i, DupConst(tokenno, s^.low, -1)) |
| END |
| END ; |
| PushValue(s^.high) ; |
| PushValue(max) ; |
| IF Less(tokenno) |
| THEN |
| i := DupConst(tokenno, s^.high, 1) ; |
| s := s^.next |
| ELSE |
| s := NIL |
| END |
| END ; |
| IF Debugging |
| THEN |
| printf0('negated set so far\n') ; |
| DisplayElements(r) |
| END ; |
| DisposeRange(v^.setValue) ; |
| PushValue(i) ; |
| PushValue(max) ; |
| IF LessEqu(tokenno) |
| THEN |
| r := AddRange(r, i, max) |
| END ; |
| IF Debugging |
| THEN |
| printf0('final negated set value\n') ; |
| DisplayElements(r) |
| END ; |
| WITH v^ DO |
| solved := FALSE ; |
| setValue := r ; |
| END ; |
| Eval(tokenno, v) ; |
| Push(v) |
| END SetNegate ; |
| |
| |
| (* |
| AddBitRange - adds the range op1..op2 to the underlying set. |
| |
| Ptr -> |
| <- Ptr |
| +------------+ +------------+ |
| | Set | | Set | |
| |------------| |------------| |
| |
| *) |
| |
| PROCEDURE AddBitRange (tokenno: CARDINAL; op1, op2: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| v := CoerseTo(tokenno, set, v) ; |
| IF v^.type=set |
| THEN |
| WITH v^ DO |
| setValue := AddRange(setValue, op1, op2) ; |
| solved := solved AND IsSolvedGCC(op1) AND IsSolvedGCC(op2) ; |
| areAllConstants := areAllConstants AND IsConst(op1) AND IsConst(op2) |
| END |
| END ; |
| Push(v) |
| END AddBitRange ; |
| |
| |
| (* |
| AddBit - adds the bit op1 to the underlying set. INCL(Set, op1) |
| |
| Ptr -> |
| <- Ptr |
| +------------+ +------------+ |
| | Set | | Set | |
| |------------| |------------| |
| *) |
| |
| PROCEDURE AddBit (tokenno: CARDINAL; op1: CARDINAL) ; |
| BEGIN |
| AddBitRange(tokenno, op1, op1) |
| END AddBit ; |
| |
| |
| (* |
| AddElementToEnd - appends, e, to the end of list, v. |
| *) |
| |
| PROCEDURE AddElementToEnd (v: PtrToValue; e: listOfElements) ; |
| VAR |
| a: listOfElements ; |
| BEGIN |
| IF v^.arrayValues=NIL |
| THEN |
| v^.arrayValues := e |
| ELSE |
| a := v^.arrayValues ; |
| WHILE a^.next#NIL DO |
| a := a^.next |
| END ; |
| a^.next := e |
| END |
| END AddElementToEnd ; |
| |
| |
| (* |
| AddFieldToEnd - appends, f, to the end of list, v. |
| *) |
| |
| PROCEDURE AddFieldToEnd (v: PtrToValue; f: listOfFields) ; |
| VAR |
| a: listOfFields ; |
| BEGIN |
| IF v^.fieldValues=NIL |
| THEN |
| v^.fieldValues := f |
| ELSE |
| a := v^.fieldValues ; |
| WHILE a^.next#NIL DO |
| a := a^.next |
| END ; |
| a^.next := f |
| END |
| END AddFieldToEnd ; |
| |
| |
| (* |
| AddField - adds the field op1 to the underlying constructor. |
| |
| Ptr -> |
| <- Ptr |
| +------------+ +------------+ |
| | const | | const | |
| |------------| |------------| |
| |
| *) |
| |
| PROCEDURE AddField (tokenno: CARDINAL; op1: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| f: listOfFields ; |
| e: listOfElements ; |
| BEGIN |
| v := Pop() ; |
| CASE v^.type OF |
| |
| set : Push(v) ; |
| AddBit(tokenno, op1) ; |
| RETURN | |
| array : WITH v^ DO |
| solved := solved AND IsSolvedGCC(op1) ; |
| areAllConstants := areAllConstants AND IsConst(op1) |
| END ; |
| NewElement(e) ; |
| WITH e^ DO |
| element := op1 ; |
| by := MakeConstLit (tokenno, MakeKey('1'), ZType) ; |
| next := NIL |
| END ; |
| AddElementToEnd(v, e) | |
| constructor, |
| record : WITH v^ DO |
| solved := solved AND IsSolvedGCC(op1) ; |
| areAllConstants := areAllConstants AND IsConst(op1) |
| END ; |
| NewField(f) ; |
| WITH f^ DO |
| field := op1 ; |
| next := NIL |
| END ; |
| AddFieldToEnd(v, f) |
| |
| ELSE |
| InternalError ('not expecting this constant type') |
| END ; |
| Push(v) |
| END AddField ; |
| |
| |
| (* |
| ElementsSolved - returns TRUE if all ranges in the set have been solved. |
| *) |
| |
| PROCEDURE ElementsSolved (tokenno: CARDINAL; r: listOfRange) : BOOLEAN ; |
| BEGIN |
| WHILE r#NIL DO |
| WITH r^ DO |
| IF NOT IsConst (low) |
| THEN |
| MetaErrorT1 (tokenno, 'a constant set can only contain constant set elements, {%1Ead} is not a constant', |
| low) |
| END ; |
| IF (high # low) AND (NOT IsConst (high)) |
| THEN |
| MetaErrorT1 (tokenno, 'a constant set can only contain constant set elements, {%1Ead} is not a constant', |
| high) |
| END ; |
| IF NOT (IsSolvedGCC(low) AND IsSolvedGCC(high)) |
| THEN |
| RETURN( FALSE ) |
| END |
| END ; |
| r := r^.next |
| END ; |
| RETURN( TRUE ) |
| END ElementsSolved ; |
| |
| |
| (* |
| ArrayElementsSolved - returns TRUE if all ranges in the set have been solved. |
| *) |
| |
| PROCEDURE ArrayElementsSolved (e: listOfElements) : BOOLEAN ; |
| BEGIN |
| WHILE e#NIL DO |
| WITH e^ DO |
| IF NOT (IsSolvedGCC(element) AND IsSolvedGCC(by)) |
| THEN |
| RETURN( FALSE ) |
| END |
| END ; |
| e := e^.next |
| END ; |
| RETURN( TRUE ) |
| END ArrayElementsSolved ; |
| |
| |
| (* |
| EvalFieldValues - returns TRUE if all fields in the record have been solved. |
| *) |
| |
| PROCEDURE EvalFieldValues (e: listOfFields) : BOOLEAN ; |
| BEGIN |
| WHILE e#NIL DO |
| WITH e^ DO |
| IF IsConst(field) |
| THEN |
| IF NOT IsSolvedGCC(field) |
| THEN |
| RETURN( FALSE ) |
| END |
| ELSE |
| (* RETURN( FALSE ) *) |
| END |
| END ; |
| e := e^.next |
| END ; |
| RETURN( TRUE ) |
| END EvalFieldValues ; |
| |
| |
| (* |
| Swap - swaps the contents of, i, and, j. |
| *) |
| |
| PROCEDURE Swap (i, j: listOfRange) ; |
| VAR |
| t: CARDINAL ; |
| BEGIN |
| t := i^.low ; |
| i^.low := j^.low ; |
| j^.low := t ; |
| |
| t := i^.high ; |
| i^.high := j^.high ; |
| j^.high := t |
| END Swap ; |
| |
| |
| (* |
| DisplayElements - |
| *) |
| |
| PROCEDURE DisplayElements (i: listOfRange) ; |
| BEGIN |
| WHILE i#NIL DO |
| PushValue(i^.low) ; |
| PrintValue ; |
| Reduce ; |
| PushValue(i^.high) ; |
| PrintValue ; |
| Reduce ; |
| i := i^.next |
| END |
| END DisplayElements ; |
| |
| |
| (* |
| SortElements - sorts the list as defined by, h, into ascending range order. |
| The low element is the sort key. |
| *) |
| |
| PROCEDURE SortElements (tokenno: CARDINAL; h: listOfRange) ; |
| VAR |
| i, j, k: listOfRange ; |
| BEGIN |
| i := h ; |
| WHILE i#NIL DO |
| j := i ; |
| k := i^.next ; |
| WHILE k#NIL DO |
| PushValue(k^.low) ; |
| ConvertToInt ; |
| PushValue(j^.low) ; |
| ConvertToInt ; |
| IF Less(tokenno) |
| THEN |
| j := k ; |
| END ; |
| k := k^.next |
| END ; |
| Swap(i, j) ; |
| i := i^.next |
| END |
| END SortElements ; |
| |
| |
| (* |
| CombineElements - given a sorted list determine whether there is any |
| overlap in the low..high bounds. If overlap exists |
| then remove it. |
| *) |
| |
| PROCEDURE CombineElements (tokenno: CARDINAL; r: listOfRange) ; |
| VAR |
| t, j: listOfRange ; |
| BEGIN |
| WHILE r#NIL DO |
| j := r^.next ; |
| WHILE j#NIL DO |
| PushValue(r^.high) ; |
| ConvertToInt ; |
| PushCard(1) ; |
| Addn ; |
| PushValue(j^.low) ; |
| ConvertToInt ; |
| IF GreEqu(tokenno) |
| THEN |
| r^.high := j^.high ; |
| t := j^.next ; |
| r^.next := j^.next ; |
| j^.next := NIL ; |
| DisposeRange(j) ; |
| j := t |
| ELSE |
| j := NIL |
| END |
| END ; |
| r := r^.next |
| END |
| END CombineElements ; |
| |
| |
| (* |
| EvalSetValues - returns TRUE if all elements in this set have been resolved. |
| *) |
| |
| PROCEDURE EvalSetValues (tokenno: CARDINAL; r: listOfRange) : BOOLEAN ; |
| BEGIN |
| IF ElementsSolved (tokenno, r) |
| THEN |
| SortElements(tokenno, r) ; |
| CombineElements(tokenno, r) ; |
| RETURN( TRUE ) |
| ELSE |
| RETURN( FALSE ) |
| END |
| END EvalSetValues ; |
| |
| |
| (* |
| Eval - attempts to solve a constructor type. |
| *) |
| |
| PROCEDURE Eval (tokenno: CARDINAL; v: PtrToValue) ; |
| BEGIN |
| CheckNotAlreadyOnFreeList(v) ; |
| WITH v^ DO |
| IF NOT solved |
| THEN |
| IF IsSet(SkipType(constructorType)) |
| THEN |
| v := CoerseTo(tokenno, set, v) |
| ELSIF IsRecord(SkipType(constructorType)) |
| THEN |
| v := CoerseTo(tokenno, record, v) |
| ELSIF IsArray(SkipType(constructorType)) |
| THEN |
| v := CoerseTo(tokenno, array, v) |
| END ; |
| areAllConstants := DefinedByConstants(v) ; |
| CASE type OF |
| |
| set : Assert((constructorType=NulSym) OR IsSet(SkipType(constructorType))) ; |
| solved := CompletelyResolved(constructorType) AND EvalSetValues(tokenno, setValue) | |
| array : Assert((constructorType=NulSym) OR IsArray(SkipType(constructorType))) ; |
| solved := CompletelyResolved(constructorType) AND ArrayElementsSolved(arrayValues) | |
| record: Assert((constructorType=NulSym) OR IsRecord(SkipType(constructorType))) ; |
| solved := CompletelyResolved(constructorType) AND EvalFieldValues(fieldValues) |
| |
| ELSE |
| (* do nothing *) |
| END |
| END |
| END |
| END Eval ; |
| |
| |
| (* |
| WalkSetValueDependants - |
| *) |
| |
| PROCEDURE WalkSetValueDependants (r: listOfRange; p: WalkAction) ; |
| BEGIN |
| WHILE r#NIL DO |
| WITH r^ DO |
| p(low) ; |
| p(high) |
| END ; |
| r := r^.next |
| END |
| END WalkSetValueDependants ; |
| |
| |
| (* |
| IsSetValueDependants - |
| *) |
| |
| PROCEDURE IsSetValueDependants (r: listOfRange; q: IsAction) : BOOLEAN ; |
| VAR |
| result: BOOLEAN ; |
| BEGIN |
| result := TRUE ; |
| WHILE r#NIL DO |
| WITH r^ DO |
| IF NOT q(low) |
| THEN |
| result := FALSE |
| END ; |
| IF NOT q(high) |
| THEN |
| result := FALSE |
| END |
| END ; |
| r := r^.next |
| END ; |
| RETURN( result ) |
| END IsSetValueDependants ; |
| |
| |
| (* |
| WalkFieldValueDependants - |
| *) |
| |
| PROCEDURE WalkFieldValueDependants (f: listOfFields; p: WalkAction) ; |
| BEGIN |
| WHILE f#NIL DO |
| WITH f^ DO |
| p(field) |
| END ; |
| f := f^.next |
| END |
| END WalkFieldValueDependants ; |
| |
| |
| (* |
| IsFieldValueDependants - |
| *) |
| |
| PROCEDURE IsFieldValueDependants (f: listOfFields; q: IsAction) : BOOLEAN ; |
| VAR |
| result: BOOLEAN ; |
| BEGIN |
| result := TRUE ; |
| WHILE f#NIL DO |
| WITH f^ DO |
| IF NOT q(field) |
| THEN |
| result := FALSE |
| END |
| END ; |
| f := f^.next |
| END ; |
| RETURN( result ) |
| END IsFieldValueDependants ; |
| |
| |
| (* |
| WalkArrayValueDependants - |
| *) |
| |
| PROCEDURE WalkArrayValueDependants (a: listOfElements; p: WalkAction) ; |
| BEGIN |
| WHILE a#NIL DO |
| WITH a^ DO |
| p(element) ; |
| p(by) |
| END ; |
| a := a^.next |
| END |
| END WalkArrayValueDependants ; |
| |
| |
| (* |
| IsArrayValueDependants - |
| *) |
| |
| PROCEDURE IsArrayValueDependants (a: listOfElements; q: IsAction) : BOOLEAN ; |
| VAR |
| result: BOOLEAN ; |
| BEGIN |
| result := TRUE ; |
| WHILE a#NIL DO |
| WITH a^ DO |
| IF NOT q(element) |
| THEN |
| result := FALSE |
| END ; |
| IF NOT q(by) |
| THEN |
| result := FALSE |
| END |
| END ; |
| a := a^.next |
| END ; |
| RETURN( result ) |
| END IsArrayValueDependants ; |
| |
| |
| (* |
| IsConstructorDependants - return TRUE if all q(dependants) of, |
| sym, return TRUE. |
| *) |
| |
| PROCEDURE IsConstructorDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ; |
| VAR |
| v : PtrToValue ; |
| typeResult, |
| result : BOOLEAN ; |
| BEGIN |
| PushValue(sym) ; |
| IF IsValueTypeNone() |
| THEN |
| v := Pop() ; |
| result := FALSE |
| ELSE |
| v := Pop() ; |
| WITH v^ DO |
| typeResult := q(constructorType) ; |
| CASE type OF |
| |
| none : result := FALSE | |
| set : result := IsSetValueDependants(setValue, q) | |
| constructor, |
| record : result := IsFieldValueDependants(fieldValues, q) | |
| array : result := IsArrayValueDependants(arrayValues, q) |
| |
| ELSE |
| InternalError ('not expecting this type') |
| END ; |
| result := result AND typeResult |
| END |
| END ; |
| RETURN( result ) |
| END IsConstructorDependants ; |
| |
| |
| (* |
| WalkConstructorDependants - walk the constructor, sym, calling |
| p for each dependant. |
| *) |
| |
| PROCEDURE WalkConstructorDependants (sym: CARDINAL; p: WalkAction) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| PushValue(sym) ; |
| IF IsValueTypeNone() |
| THEN |
| v := Pop() |
| ELSE |
| v := Pop() ; |
| WITH v^ DO |
| p(constructorType) ; |
| CASE type OF |
| |
| none : | |
| set : WalkSetValueDependants(setValue, p) | |
| constructor, |
| record : WalkFieldValueDependants(fieldValues, p) | |
| array : WalkArrayValueDependants(arrayValues, p) |
| |
| ELSE |
| InternalError ('not expecting this type') |
| END |
| END |
| END |
| END WalkConstructorDependants ; |
| |
| |
| (* |
| PutConstructorSolved - records that this constructor is solved. |
| *) |
| |
| PROCEDURE PutConstructorSolved (sym: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| PushValue(sym) ; |
| v := Pop() ; |
| v^.solved := TRUE ; |
| Push(v) ; |
| PopValue(sym) |
| END PutConstructorSolved ; |
| |
| |
| (* |
| EvaluateValue - attempts to evaluate the symbol, sym, value. |
| *) |
| |
| PROCEDURE EvaluateValue (sym: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| PushValue(sym) ; |
| v := Pop() ; |
| Eval(GetDeclaredMod(sym), v) ; |
| Push(v) ; |
| PopValue(sym) |
| END EvaluateValue ; |
| |
| |
| (* |
| TryEvaluateValue - attempts to evaluate the symbol, sym, value. |
| *) |
| |
| PROCEDURE TryEvaluateValue (sym: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| PushValue(sym) ; |
| v := Pop() ; |
| WITH v^ DO |
| CASE type OF |
| |
| set, array, record: IF v^.constructorType=NulSym |
| THEN |
| (* must wait *) |
| RETURN |
| ELSE |
| Eval(GetDeclaredMod(sym), v) |
| END |
| |
| ELSE |
| (* nothing to do *) |
| END ; |
| IF solved |
| THEN |
| Push(v) ; |
| PopValue(sym) |
| END |
| END |
| END TryEvaluateValue ; |
| |
| |
| (* |
| DefinedByConstants - returns TRUE if the value, v, is defined by constants. |
| It assigns, v^.areAllConstants, with the result. |
| *) |
| |
| PROCEDURE DefinedByConstants (v: PtrToValue) : BOOLEAN ; |
| BEGIN |
| WITH v^ DO |
| CASE type OF |
| |
| none, |
| integer, |
| real, |
| complex : areAllConstants := TRUE | |
| set : areAllConstants := rangeConstant(setValue) | |
| constructor, |
| record : areAllConstants := fieldsConstant(fieldValues) | |
| array : areAllConstants := arrayConstant(arrayValues) |
| |
| ELSE |
| InternalError ('unexpected type') |
| END ; |
| RETURN( areAllConstants ) |
| END |
| END DefinedByConstants ; |
| |
| |
| (* |
| rangeConstant - returns TRUE if all the range entities are constant. |
| *) |
| |
| PROCEDURE rangeConstant (r: listOfRange) : BOOLEAN ; |
| BEGIN |
| WHILE r#NIL DO |
| IF (NOT IsConst(r^.low)) OR (NOT IsConst(r^.high)) |
| THEN |
| RETURN( FALSE ) |
| END ; |
| r := r^.next ; |
| END ; |
| RETURN( TRUE ) |
| END rangeConstant ; |
| |
| |
| (* |
| fieldsConstant - returns TRUE if all the field entities are constant. |
| *) |
| |
| PROCEDURE fieldsConstant (f: listOfFields) : BOOLEAN ; |
| BEGIN |
| WHILE f#NIL DO |
| IF NOT IsConst(f^.field) |
| THEN |
| RETURN( FALSE ) |
| END ; |
| f := f^.next |
| END ; |
| RETURN( TRUE ) |
| END fieldsConstant ; |
| |
| |
| (* |
| arrayConstant - returns TRUE if the, element, and, by, components |
| of an array constructor are constant. |
| *) |
| |
| PROCEDURE arrayConstant (e: listOfElements) : BOOLEAN ; |
| BEGIN |
| WHILE e#NIL DO |
| IF (NOT IsConst(e^.element)) AND (NOT IsConst(e^.by)) |
| THEN |
| RETURN( FALSE ) |
| END ; |
| e := e^.next |
| END ; |
| RETURN( TRUE ) |
| END arrayConstant ; |
| |
| |
| (* |
| FindValueEnum - |
| *) |
| |
| PROCEDURE FindValueEnum (field: WORD) ; |
| BEGIN |
| PushValue(field) ; |
| PushIntegerTree(EnumerationValue) ; |
| IF Equ(CurrentTokenNo) |
| THEN |
| EnumerationField := field |
| END |
| END FindValueEnum ; |
| |
| |
| (* |
| Val - returns a GCC symbol enumeration or a GCC constant which has, value, and which is |
| of type, type. |
| *) |
| |
| PROCEDURE Val (tokenno: CARDINAL; type: CARDINAL; value: tree) : CARDINAL ; |
| VAR |
| sym: CARDINAL ; |
| BEGIN |
| IF IsEnumeration(type) |
| THEN |
| EnumerationField := NulSym ; |
| EnumerationValue := value ; |
| CurrentTokenNo := tokenno ; |
| ForeachFieldEnumerationDo(type, FindValueEnum) ; |
| IF EnumerationField=NulSym |
| THEN |
| InternalError ('enumeration value exceeds range') |
| END ; |
| RETURN( EnumerationField ) |
| ELSE |
| sym := MakeTemporary(tokenno, ImmediateValue) ; |
| PutVar(sym, type) ; |
| CheckOverflow(tokenno, value) ; |
| PushIntegerTree(value) ; |
| PopValue(sym) ; |
| RETURN( sym ) |
| END |
| END Val ; |
| |
| |
| (* |
| DupConst - duplicates and returns a constant, sym, but adds, offset to its value. |
| *) |
| |
| PROCEDURE DupConst (tokenno: CARDINAL; sym: CARDINAL; offset: INTEGER) : CARDINAL ; |
| BEGIN |
| PushValue(sym) ; |
| PushInt(offset) ; |
| Addn ; |
| RETURN( Val(tokenno, GetType(sym), PopIntegerTree()) ) |
| END DupConst ; |
| |
| |
| (* |
| DupConstAndAdd - duplicates and returns a constant, sym, |
| but adds the symbol, extra. |
| *) |
| |
| PROCEDURE DupConstAndAdd (tokenno: CARDINAL; |
| sym: CARDINAL; extra: tree) : CARDINAL ; |
| BEGIN |
| PushValue(sym) ; |
| PushIntegerTree(extra) ; |
| Addn ; |
| RETURN( Val(tokenno, GetType(sym), PopIntegerTree()) ) |
| END DupConstAndAdd ; |
| |
| |
| (* |
| DupConstAndAddMod - duplicates and returns a constant, sym, |
| but adds the symbol, extra, and ensures that |
| the result in within limits: min..max using |
| modulo arithmetic. |
| *) |
| |
| PROCEDURE DupConstAndAddMod (tokenno: CARDINAL; |
| sym: CARDINAL; extra: tree; |
| l, h: CARDINAL) : CARDINAL ; |
| BEGIN |
| (* result := (((sym-l) + extra) MOD (h-l)) + l) *) |
| PushValue(sym) ; |
| PushValue(l) ; |
| Sub ; |
| PushIntegerTree(extra) ; |
| Addn ; |
| PushValue(h) ; |
| PushValue(l) ; |
| Sub ; |
| ModTrunc ; |
| PushValue(l) ; |
| Addn ; |
| RETURN( Val(tokenno, GetType(sym), PopIntegerTree()) ) |
| END DupConstAndAddMod ; |
| |
| |
| (* |
| Remove - removes, v, from list, h. |
| *) |
| |
| PROCEDURE Remove (VAR h: listOfRange; v: listOfRange) ; |
| VAR |
| i: listOfRange ; |
| BEGIN |
| IF h=v |
| THEN |
| h := h^.next |
| ELSE |
| i := h ; |
| WHILE (i#NIL) AND (i^.next#v) DO |
| i := i^.next |
| END ; |
| IF i=NIL |
| THEN |
| InternalError ('expecting v to be on the list') |
| ELSE |
| i := v^.next |
| END |
| END ; |
| v^.next := NIL ; |
| DisposeRange(v) |
| END Remove ; |
| |
| |
| (* |
| RemoveBit - remove bit, op1, from range, v, on list, h. |
| *) |
| |
| PROCEDURE RemoveBit (tokenno: CARDINAL; VAR h: listOfRange; v: listOfRange; op1: CARDINAL) ; |
| BEGIN |
| WITH v^ DO |
| PushValue(low) ; |
| PushValue(high) ; |
| IF Equ(tokenno) |
| THEN |
| (* single bit in this range *) |
| PushValue(low) ; |
| PushValue(op1) ; |
| IF Equ(tokenno) |
| THEN |
| (* remove entry *) |
| Remove(h, v) ; |
| RETURN |
| END |
| ELSE |
| (* is op1 equal to low? *) |
| PushValue(op1) ; |
| PushValue(low) ; |
| IF Equ(tokenno) |
| THEN |
| low := DupConst(tokenno, low, 1) |
| ELSE |
| PushValue(op1) ; |
| PushValue(high) ; |
| IF Equ(tokenno) |
| THEN |
| high := DupConst(tokenno, high, -1) |
| ELSE |
| high := DupConst(tokenno, op1, -1) ; |
| h := AddRange(h, DupConst(tokenno, op1, 1), high) ; |
| SortElements(tokenno, h) |
| END |
| END |
| END |
| END |
| END RemoveBit ; |
| |
| |
| (* |
| PerformSubBit - |
| *) |
| |
| PROCEDURE PerformSubBit (tokenno: CARDINAL; VAR h: listOfRange; op1: CARDINAL) ; |
| VAR |
| v: listOfRange ; |
| BEGIN |
| v := h ; |
| WHILE v#NIL DO |
| WITH v^ DO |
| PushValue(low) ; |
| PushValue(op1) ; |
| IF LessEqu(tokenno) |
| THEN |
| PushValue(op1) ; |
| PushValue(high) ; |
| IF LessEqu(tokenno) |
| THEN |
| RemoveBit(tokenno, h, v, op1) ; |
| RETURN |
| END |
| END |
| END ; |
| v := v^.next |
| END |
| END PerformSubBit ; |
| |
| |
| (* |
| SubBit - removes a bit op1 from the underlying set. EXCL(Set, Op1) |
| |
| Ptr -> |
| <- Ptr |
| +------------+ +------------+ |
| | Set | | Set | |
| |------------| |------------| |
| *) |
| |
| PROCEDURE SubBit (tokenno: CARDINAL; op1: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| IF v^.type=set |
| THEN |
| Eval(tokenno, v) ; |
| WITH v^ DO |
| IF solved |
| THEN |
| IF IsSolvedGCC(op1) |
| THEN |
| PerformSubBit(tokenno, setValue, op1) ; |
| solved := FALSE |
| ELSE |
| InternalError ('can only subtract a bit from a set when the bit value is known') |
| END |
| ELSE |
| InternalError ('can only subtract a bit from a set when the set value is known') |
| END |
| END ; |
| Eval(tokenno, v) |
| ELSE |
| InternalError ('expecting set type constant') |
| END ; |
| Push(v) |
| END SubBit ; |
| |
| |
| (* |
| PerformSetIn - returns TRUE if op1 is in set. |
| *) |
| |
| PROCEDURE PerformSetIn (tokenno: CARDINAL; op1: CARDINAL; h: listOfRange) : BOOLEAN ; |
| BEGIN |
| WHILE h#NIL DO |
| WITH h^ DO |
| PushValue(op1) ; |
| ConvertToInt ; |
| PushValue(low) ; |
| ConvertToInt ; |
| IF GreEqu(tokenno) |
| THEN |
| PushValue(op1) ; |
| PushValue(high) ; |
| IF LessEqu(tokenno) |
| THEN |
| RETURN( TRUE ) |
| END |
| ELSE |
| (* op1 is smaller than this and all subsequent ranges *) |
| RETURN( FALSE ) |
| END |
| END ; |
| h := h^.next |
| END ; |
| RETURN( FALSE ) |
| END PerformSetIn ; |
| |
| |
| (* |
| SetIn - returns true if Op2 IN Op1 |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Set | |
| |------------| Empty |
| |
| RETURN( Op1 IN Set ) |
| *) |
| |
| PROCEDURE SetIn (tokenno: CARDINAL; Op1: CARDINAL) : BOOLEAN ; |
| VAR |
| Set : PtrToValue ; |
| result: BOOLEAN ; |
| BEGIN |
| Set := Pop() ; |
| IF Set^.type#set |
| THEN |
| InternalError ('expecting ALU operand to be a set') |
| END ; |
| Eval(tokenno, Set) ; |
| IF IsSolvedGCC(Op1) AND Set^.solved |
| THEN |
| result := PerformSetIn(tokenno, Op1, Set^.setValue) |
| ELSE |
| InternalError ('one or more operands have not been resolved') |
| END ; |
| Dispose(Set) ; |
| RETURN( result ) |
| END SetIn ; |
| |
| |
| (* |
| SetOp - perform the function doOp on the top two elements of the stack. |
| *) |
| |
| PROCEDURE SetOp (tokenno: CARDINAL; doOp: DoSetProcedure) ; |
| VAR |
| Result, |
| Set1, Set2: PtrToValue ; |
| BEGIN |
| Set1 := Pop() ; |
| Set2 := Pop() ; |
| Eval(tokenno, Set1) ; |
| Eval(tokenno, Set2) ; |
| IF NOT (Set1^.solved AND Set2^.solved) |
| THEN |
| InternalError ('one or more operands have not been resolved') |
| END ; |
| IF Set1^.type#set |
| THEN |
| InternalError ('expecting type of constant to be a set') |
| END ; |
| IF Set2^.type#set |
| THEN |
| InternalError ('expecting type of constant to be a set') |
| END ; |
| Result := New() ; |
| WITH Result^ DO |
| type := set ; |
| setValue := doOp(tokenno, Set1^.setValue, Set2^.setValue) ; |
| constructorType := MixTypes(Set1^.constructorType, |
| Set2^.constructorType, tokenno) ; |
| solved := FALSE |
| END ; |
| (* Set1 and Set2 have given their range lists to the Result *) |
| Set1^.setValue := NIL ; |
| Set2^.setValue := NIL ; |
| Eval(tokenno, Result) ; |
| Push(Result) ; |
| Dispose(Set1) ; |
| Dispose(Set2) |
| END SetOp ; |
| |
| |
| (* |
| PerformOr - performs a logical OR between the two ranges. |
| The ranges, r1, r2, are destroyed. |
| *) |
| |
| PROCEDURE PerformOr (tokenno: CARDINAL; r1, r2: listOfRange) : listOfRange ; |
| VAR |
| i: listOfRange ; |
| BEGIN |
| i := r1 ; |
| WHILE (i#NIL) AND (i^.next#NIL) DO |
| i := i^.next |
| END ; |
| IF i=NIL |
| THEN |
| r1 := r2 |
| ELSE |
| i^.next := r2 |
| END ; |
| SortElements(tokenno, r1) ; |
| CombineElements(tokenno, r1) ; |
| RETURN( r1 ) |
| END PerformOr ; |
| |
| |
| (* |
| SetOr - performs an inclusive OR of the top two elements on the stack. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Set1 | <- Ptr |
| |------------| +------------+ |
| | Set2 | | Set1 + Set2| |
| |------------| |------------| |
| |
| *) |
| |
| PROCEDURE SetOr (tokenno: CARDINAL) ; |
| BEGIN |
| SetOp(tokenno, PerformOr) |
| END SetOr ; |
| |
| |
| (* |
| Min - returns the symbol which has the least value. |
| *) |
| |
| PROCEDURE Min (tokenno: CARDINAL; a, b: CARDINAL) : CARDINAL ; |
| BEGIN |
| PushValue(a) ; |
| ConvertToInt ; |
| PushValue(b) ; |
| ConvertToInt ; |
| IF Less(tokenno) |
| THEN |
| RETURN( a ) |
| ELSE |
| RETURN( b ) |
| END |
| END Min ; |
| |
| |
| (* |
| Max - returns the symbol which has the greatest value. |
| *) |
| |
| PROCEDURE Max (tokenno: CARDINAL; a, b: CARDINAL) : CARDINAL ; |
| BEGIN |
| PushValue(a) ; |
| ConvertToInt ; |
| PushValue(b) ; |
| ConvertToInt ; |
| IF Gre(tokenno) |
| THEN |
| RETURN( a ) |
| ELSE |
| RETURN( b ) |
| END |
| END Max ; |
| |
| |
| (* |
| IsRangeIntersection - returns TRUE if ranges, r1, and, r2, intersect. |
| *) |
| |
| PROCEDURE IsRangeIntersection (tokenno: CARDINAL; r1, r2: listOfRange) : BOOLEAN ; |
| BEGIN |
| IF (r1=NIL) OR (r2=NIL) |
| THEN |
| RETURN( FALSE ) |
| ELSE |
| (* easier to prove NOT outside limits *) |
| PushValue(r1^.low) ; |
| ConvertToInt ; |
| PushValue(r2^.high) ; |
| ConvertToInt ; |
| IF Gre(tokenno) |
| THEN |
| RETURN( FALSE ) |
| ELSE |
| PushValue(r1^.high) ; |
| ConvertToInt ; |
| PushValue(r2^.low) ; |
| ConvertToInt ; |
| IF Less(tokenno) |
| THEN |
| RETURN( FALSE ) |
| ELSE |
| RETURN( TRUE ) |
| END |
| END |
| END |
| END IsRangeIntersection ; |
| |
| |
| (* |
| IsRangeLess - returns TRUE if r1^.low is < r2^.low |
| *) |
| |
| PROCEDURE IsRangeLess (tokenno: CARDINAL; r1, r2: listOfRange) : BOOLEAN ; |
| BEGIN |
| IF (r1=NIL) OR (r2=NIL) |
| THEN |
| InternalError ('not expecting NIL ranges') |
| END ; |
| PushValue(r1^.high) ; |
| ConvertToInt ; |
| PushValue(r2^.low) ; |
| ConvertToInt ; |
| RETURN( Less(tokenno) ) |
| END IsRangeLess ; |
| |
| |
| (* |
| MinTree - returns the tree symbol which has the least value. |
| *) |
| |
| PROCEDURE MinTree (tokenno: CARDINAL; a, b: tree) : tree ; |
| BEGIN |
| PushIntegerTree(a) ; |
| ConvertToInt ; |
| PushIntegerTree(b) ; |
| ConvertToInt ; |
| IF Less(tokenno) |
| THEN |
| RETURN( a ) |
| ELSE |
| RETURN( b ) |
| END |
| END MinTree ; |
| |
| |
| (* |
| MaxTree - returns the symbol which has the greatest value. |
| *) |
| |
| PROCEDURE MaxTree (tokenno: CARDINAL; a, b: tree) : tree ; |
| BEGIN |
| PushIntegerTree(a) ; |
| ConvertToInt ; |
| PushIntegerTree(b) ; |
| ConvertToInt ; |
| IF Gre(tokenno) |
| THEN |
| RETURN( a ) |
| ELSE |
| RETURN( b ) |
| END |
| END MaxTree ; |
| |
| |
| (* |
| IsIntersectionTree - returns TRUE if ranges, a..b, and, c..d, intersect. |
| *) |
| |
| PROCEDURE IsIntersectionTree (tokenno: CARDINAL; a, b, c, d: tree) : BOOLEAN ; |
| BEGIN |
| (* easier to prove NOT outside limits *) |
| PushIntegerTree(a) ; |
| ConvertToInt ; |
| PushIntegerTree(d) ; |
| ConvertToInt ; |
| IF Gre(tokenno) |
| THEN |
| RETURN( FALSE ) |
| ELSE |
| PushIntegerTree(b) ; |
| ConvertToInt ; |
| PushIntegerTree(c) ; |
| ConvertToInt ; |
| IF Less(tokenno) |
| THEN |
| RETURN( FALSE ) |
| ELSE |
| RETURN( TRUE ) |
| END |
| END |
| END IsIntersectionTree ; |
| |
| |
| (* |
| SubTree - returns the tree value containing (a-b) |
| *) |
| |
| PROCEDURE SubTree (a, b: tree) : tree ; |
| BEGIN |
| PushIntegerTree(a) ; |
| PushIntegerTree(b) ; |
| Sub ; |
| RETURN( PopIntegerTree() ) |
| END SubTree ; |
| |
| |
| (* |
| PerformAnd - performs a logical AND between the two ranges. |
| The ranges, r1, r2, are unaltered. |
| *) |
| |
| PROCEDURE PerformAnd (tokenno: CARDINAL; r1, r2: listOfRange) : listOfRange ; |
| VAR |
| r: listOfRange ; |
| BEGIN |
| r := NIL ; |
| WHILE (r1#NIL) AND (r2#NIL) DO |
| IF IsRangeIntersection(tokenno, r1, r2) |
| THEN |
| r := AddRange(r, Max(tokenno, r1^.low, r2^.low), Min(tokenno, r1^.high, r2^.high)) ; |
| IF r^.high=r1^.high |
| THEN |
| r1 := r1^.next |
| ELSE |
| r2 := r2^.next |
| END |
| ELSIF IsRangeLess(tokenno, r1, r2) |
| THEN |
| (* move r1 onto the next range *) |
| r1 := r1^.next |
| ELSE |
| (* move r2 onto the next range *) |
| r2 := r2^.next |
| END |
| END ; |
| RETURN( r ) |
| END PerformAnd ; |
| |
| |
| (* |
| SetAnd - performs a set AND the top two elements on the stack. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | <- Ptr |
| |------------| +------------+ |
| | Op2 | | Op2 * Op1 | |
| |------------| |------------| |
| *) |
| |
| PROCEDURE SetAnd (tokenno: CARDINAL) ; |
| BEGIN |
| SetOp(tokenno, PerformAnd) |
| END SetAnd ; |
| |
| |
| (* |
| SetDifference - performs a set difference of the top two elements on the stack. |
| For each member in the set |
| if member in Op2 and not member in Op1 |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | <- Ptr |
| |------------| +-------------------+ |
| | Op2 | | Op2 and (not Op1) | |
| |------------| |-------------------| |
| *) |
| |
| PROCEDURE SetDifference (tokenno: CARDINAL) ; |
| VAR |
| Set1, Set2: PtrToValue ; |
| BEGIN |
| Set1 := Pop() ; |
| Set2 := Pop() ; |
| Eval(tokenno, Set1) ; |
| Eval(tokenno, Set2) ; |
| IF NOT (Set1^.solved AND Set2^.solved) |
| THEN |
| InternalError ('one or more operands have not been resolved') |
| END ; |
| IF Set1^.setValue=NIL |
| THEN |
| (* null set, return Set2 *) |
| Push(Set1) ; |
| ELSE |
| Push(Set1) ; |
| SetNegate(tokenno) ; |
| Push(Set2) ; |
| SetAnd(tokenno) |
| END |
| END SetDifference ; |
| |
| |
| (* |
| SetSymmetricDifference - performs a set difference of the top two elements on the stack. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | <- Ptr |
| |------------| +-------------+ |
| | Op2 | | Op2 xor Op1 | |
| |------------| |-------------| |
| *) |
| |
| PROCEDURE SetSymmetricDifference (tokenno: CARDINAL) ; |
| VAR |
| Set1, Set2: PtrToValue ; |
| BEGIN |
| Set1 := Pop() ; |
| Set2 := Pop() ; |
| Eval(tokenno, Set1) ; |
| Eval(tokenno, Set2) ; |
| IF NOT (Set1^.solved AND Set2^.solved) |
| THEN |
| InternalError ('one or more operands have not been resolved') |
| END ; |
| IF Set1^.setValue=NIL |
| THEN |
| Dispose(Set1) ; |
| Push(Set2) |
| ELSIF Set2^.setValue=NIL |
| THEN |
| Dispose(Set2) ; |
| Push(Set1) |
| ELSE |
| (* Set1 or Set2 and (not (Set1 and Set2)) *) |
| PushFrom(Set1) ; |
| PushFrom(Set2) ; |
| SetAnd(tokenno) ; |
| SetNegate(tokenno) ; |
| Push(Set1) ; |
| Push(Set2) ; |
| SetOr(tokenno) ; |
| SetAnd(tokenno) |
| END |
| END SetSymmetricDifference ; |
| |
| |
| (* |
| SetShift - if op1 is positive |
| then |
| result := op2 << op1 |
| else |
| result := op2 >> op1 |
| fi |
| |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | <- Ptr |
| |------------| +------------+ |
| | Op2 | | result | |
| |------------| |------------| |
| |
| *) |
| |
| PROCEDURE SetShift (tokenno: CARDINAL) ; |
| VAR |
| res, |
| Shift, |
| Set : PtrToValue ; |
| n : CARDINAL ; |
| r1, r2 : CARDINAL ; |
| BEGIN |
| IF NOT IsValueTypeInteger() |
| THEN |
| InternalError ('expecting integer type') |
| END ; |
| Shift := Pop() ; |
| IF NOT IsValueTypeSet() |
| THEN |
| InternalError ('expecting set type') |
| END ; |
| Set := Pop() ; |
| Eval(tokenno, Set) ; |
| IF NOT Set^.solved |
| THEN |
| InternalError ('set has not been resolved') |
| END ; |
| IF Set^.setValue=NIL |
| THEN |
| Push(Set) |
| ELSE |
| res := New() ; |
| res^ := Set^ ; |
| WITH res^ DO |
| setValue := NIL ; |
| n := 1 ; |
| WHILE GetRange(Set, n, r1, r2) DO |
| setValue := AddRange(setValue, |
| DupConstAndAdd(tokenno, r1, Shift), |
| DupConstAndAdd(tokenno, r2, Shift)) ; |
| INC(n) |
| END ; |
| Push(res) ; |
| IF constructorType#NulSym |
| THEN |
| PushNulSet(constructorType) ; |
| SetNegate(tokenno) ; |
| SetAnd(tokenno) |
| END |
| END ; |
| Dispose(Set) |
| END |
| END SetShift ; |
| |
| |
| (* |
| SetRotate - if op1 is positive |
| then |
| result := ROTATERIGHT(op2, op1) |
| else |
| result := ROTATELEFT(op2, op1) |
| fi |
| |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | <- Ptr |
| |------------| +------------+ |
| | Op2 | | result | |
| |------------| |------------| |
| *) |
| |
| PROCEDURE SetRotate (tokenno: CARDINAL) ; |
| VAR |
| res, |
| Rotate, |
| Set : PtrToValue ; |
| n : CARDINAL ; |
| l, h, |
| type, |
| r1, r2 : CARDINAL ; |
| BEGIN |
| IF NOT IsValueTypeInteger() |
| THEN |
| InternalError ('expecting integer type') |
| END ; |
| Rotate := Pop() ; |
| IF NOT IsValueTypeSet() |
| THEN |
| InternalError ('expecting set type') |
| END ; |
| Set := Pop() ; |
| Eval(tokenno, Set) ; |
| IF NOT Set^.solved |
| THEN |
| InternalError ('set has not been resolved') |
| END ; |
| IF Set^.setValue=NIL |
| THEN |
| Push(Set) |
| ELSE |
| type := Set^.constructorType ; |
| IF type=NulSym |
| THEN |
| MetaErrorT0 (tokenno, 'cannot perform a ROTATE on a generic set') ; |
| Push(Set) ; |
| RETURN |
| END ; |
| l := GetTypeMin(type) ; |
| h := GetTypeMax(type) ; |
| res := New() ; |
| res^ := Set^ ; |
| WITH res^ DO |
| setValue := NIL ; |
| n := 1 ; |
| WHILE GetRange(Set, n, r1, r2) DO |
| setValue := AddRange(setValue, |
| DupConstAndAddMod(tokenno, r1, Rotate, l, h), |
| DupConstAndAddMod(tokenno, r2, Rotate, l, h)) ; |
| INC(n) |
| END |
| END ; |
| Push(res) ; |
| Dispose(Set) |
| END |
| END SetRotate ; |
| |
| |
| (* |
| GetValue - returns and pops the value from the top of stack. |
| *) |
| |
| PROCEDURE GetValue (tokenno: CARDINAL) : PtrToValue ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| Eval(tokenno, v) ; |
| RETURN( v ) |
| END GetValue ; |
| |
| |
| (* |
| GetRange - returns TRUE if range number, n, exists in the value, v. |
| A non empty set is defined by having 1..N ranges |
| *) |
| |
| PROCEDURE GetRange (v: PtrToValue; n: CARDINAL; VAR low, high: CARDINAL) : BOOLEAN ; |
| VAR |
| l: listOfRange ; |
| BEGIN |
| WITH v^ DO |
| IF type#set |
| THEN |
| InternalError ('expecting set constant') |
| END ; |
| l := setValue ; |
| WHILE n>1 DO |
| IF l=NIL |
| THEN |
| RETURN( FALSE ) |
| END ; |
| l := l^.next ; |
| DEC(n) |
| END ; |
| IF l=NIL |
| THEN |
| RETURN( FALSE ) |
| END ; |
| low := l^.low ; |
| high := l^.high |
| END ; |
| RETURN( TRUE ) |
| END GetRange ; |
| |
| |
| (* |
| BuildStructBitset - v is the PtrToValue. |
| low and high are the limits of the subrange. |
| *) |
| |
| PROCEDURE BuildStructBitset (tokenno: CARDINAL; v: PtrToValue; low, high: tree) : tree ; |
| VAR |
| BitsInSet : tree ; |
| bpw : CARDINAL ; |
| cons : Constructor ; |
| BEGIN |
| PushIntegerTree(low) ; |
| ConvertToInt ; |
| low := PopIntegerTree() ; |
| PushIntegerTree(high) ; |
| ConvertToInt ; |
| high := PopIntegerTree() ; |
| bpw := GetBitsPerBitset() ; |
| |
| PushIntegerTree(high) ; |
| PushIntegerTree(low) ; |
| Sub ; |
| PushCard(1) ; |
| Addn ; |
| BitsInSet := PopIntegerTree() ; |
| |
| cons := BuildStartSetConstructor(Mod2Gcc(v^.constructorType)) ; |
| |
| PushIntegerTree(BitsInSet) ; |
| PushCard(0) ; |
| WHILE Gre(tokenno) DO |
| PushIntegerTree(BitsInSet) ; |
| PushCard(bpw-1) ; |
| IF GreEqu(tokenno) |
| THEN |
| PushIntegerTree(low) ; |
| PushCard(bpw-1) ; |
| Addn ; |
| |
| BuildSetConstructorElement(cons, BuildBitset(tokenno, v, low, PopIntegerTree())) ; |
| |
| PushIntegerTree(low) ; |
| PushCard(bpw) ; |
| Addn ; |
| low := PopIntegerTree() ; |
| PushIntegerTree(BitsInSet) ; |
| PushCard(bpw) ; |
| Sub ; |
| BitsInSet := PopIntegerTree() |
| ELSE |
| (* printf2('range is %a..%a\n', GetSymName(low), GetSymName(high)) ; *) |
| |
| BuildSetConstructorElement(cons, BuildBitset(tokenno, v, low, high)) ; |
| |
| PushCard(0) ; |
| BitsInSet := PopIntegerTree() |
| END ; |
| PushIntegerTree(BitsInSet) ; |
| PushCard(0) |
| END ; |
| RETURN( BuildEndSetConstructor(cons) ) |
| END BuildStructBitset ; |
| |
| |
| (* |
| ConstructLargeOrSmallSet - generates a constant representing the set value of the symbol, sym. |
| We manufacture the constant by using a initialization |
| structure of cardinals. |
| |
| { (cardinal), (cardinal) etc } |
| *) |
| |
| PROCEDURE ConstructLargeOrSmallSet (tokenno: CARDINAL; v: PtrToValue; low, high: CARDINAL) : tree ; |
| BEGIN |
| PushValue(high) ; |
| ConvertToInt ; |
| PushValue(low) ; |
| ConvertToInt ; |
| Sub ; |
| PushCard(GetBitsPerBitset()) ; |
| IF Less(tokenno) |
| THEN |
| (* small set *) |
| RETURN( BuildBitset(tokenno, v, Mod2Gcc(low), Mod2Gcc(high)) ) |
| ELSE |
| (* large set *) |
| RETURN( BuildStructBitset(tokenno, v, Mod2Gcc(low), Mod2Gcc(high)) ) |
| END |
| END ConstructLargeOrSmallSet ; |
| |
| |
| (* |
| ConstructSetConstant - builds a struct of integers which represents the |
| set const as defined by, v. |
| *) |
| |
| PROCEDURE ConstructSetConstant (tokenno: CARDINAL; v: PtrToValue) : tree ; |
| VAR |
| n1, n2 : Name ; |
| gccsym : tree ; |
| baseType, |
| high, low: CARDINAL ; |
| BEGIN |
| WITH v^ DO |
| IF constructorType=NulSym |
| THEN |
| InternalError ('set type must be known in order to generate a constant') |
| ELSE |
| baseType := SkipType(GetType(constructorType)) ; |
| IF Debugging |
| THEN |
| n1 := GetSymName(constructorType) ; |
| n2 := GetSymName(baseType) ; |
| printf2('ConstructSetConstant of type %a and baseType %a\n', n1, n2) |
| END ; |
| IF IsSubrange(baseType) |
| THEN |
| GetSubrange(baseType, high, low) ; |
| gccsym := ConstructLargeOrSmallSet(tokenno, v, low, high) |
| ELSE |
| gccsym := ConstructLargeOrSmallSet(tokenno, v, GetTypeMin(baseType), GetTypeMax(baseType)) |
| END ; |
| RETURN( gccsym ) |
| END |
| END |
| END ConstructSetConstant ; |
| |
| |
| (* |
| ConvertConstToType - returns a Tree containing an initialiser, |
| init, ready to be assigned to a record or |
| array constructor. |
| *) |
| |
| PROCEDURE ConvertConstToType (tokenno: CARDINAL; field: CARDINAL; init: CARDINAL) : tree ; |
| VAR |
| initT, |
| nBytes: tree ; |
| BEGIN |
| IF IsConstString(init) AND IsArray(SkipType(GetType(field))) AND |
| (SkipTypeAndSubrange(GetType(GetType(field)))=Char) |
| THEN |
| IF NOT PrepareCopyString (tokenno, nBytes, initT, init, GetType (field)) |
| THEN |
| MetaErrorT2 (tokenno, |
| 'string constant {%1Ea} is too large to be assigned to the {%2d} {%2a}', |
| init, field) |
| END ; |
| RETURN initT |
| ELSE |
| RETURN( ConvertConstantAndCheck(TokenToLocation(tokenno), Mod2Gcc(GetType(field)), Mod2Gcc(init)) ) |
| END |
| END ConvertConstToType ; |
| |
| |
| (* |
| ConstructRecordConstant - builds a struct initializer, as defined by, v. |
| *) |
| |
| PROCEDURE ConstructRecordConstant (tokenno: CARDINAL; v: PtrToValue) : tree ; |
| VAR |
| n1, n2 : Name ; |
| i, |
| Field, |
| baseType : CARDINAL ; |
| cons : Constructor ; |
| BEGIN |
| WITH v^ DO |
| IF constructorType=NulSym |
| THEN |
| InternalError ('record type must be known in order to generate a constant') |
| ELSE |
| baseType := SkipType(constructorType) ; |
| IF Debugging |
| THEN |
| n1 := GetSymName(constructorType) ; |
| n2 := GetSymName(baseType) ; |
| printf2('ConstructRecordConstant of type %a and baseType %a\n', n1, n2) |
| END ; |
| cons := BuildStartRecordConstructor(Mod2Gcc(baseType)) ; |
| i := 1 ; |
| REPEAT |
| Field := GetNth(baseType, i) ; |
| IF Field#NulSym |
| THEN |
| IF GccKnowsAbout(GetType(Field)) |
| THEN |
| BuildRecordConstructorElement(cons, ConvertConstToType(tokenno, Field, GetConstructorField(v, i))) |
| ELSE |
| MetaErrorT0 (tokenno, 'trying to construct a compound literal and using a record field which does not exist') |
| END |
| END ; |
| INC(i) |
| UNTIL Field=NulSym ; |
| RETURN( BuildEndRecordConstructor(cons) ) |
| END |
| END |
| END ConstructRecordConstant ; |
| |
| |
| (* |
| GetConstructorField - returns a symbol containing the constructor field, i. |
| *) |
| |
| PROCEDURE GetConstructorField (v: PtrToValue; i: CARDINAL) : CARDINAL ; |
| VAR |
| j: CARDINAL ; |
| f: listOfFields ; |
| BEGIN |
| WITH v^ DO |
| IF type#record |
| THEN |
| InternalError ('constructor type must be a record in order to push a field') |
| ELSE |
| IF constructorType=NulSym |
| THEN |
| InternalError ('constructor type must be a record in order to push a field') |
| ELSE |
| j := 1 ; |
| f := fieldValues ; |
| WHILE (j<i) AND (f#NIL) DO |
| f := f^.next ; |
| INC(j) |
| END ; |
| IF f=NIL |
| THEN |
| MetaError1 ('the {%1EN} element does not exist in the constant compound literal', i) ; |
| RETURN( NulSym ) |
| ELSE |
| RETURN( f^.field ) |
| END |
| END |
| END |
| END |
| END GetConstructorField ; |
| |
| |
| (* |
| GetConstructorElement - returns a symbol containing the array constructor element, i. |
| *) |
| |
| PROCEDURE GetConstructorElement (tokenno: CARDINAL; v: PtrToValue; i: CARDINAL) : CARDINAL ; |
| VAR |
| j: tree ; |
| e: listOfElements ; |
| BEGIN |
| WITH v^ DO |
| IF type#array |
| THEN |
| InternalError ('constructor type must be an array') |
| ELSE |
| IF constructorType=NulSym |
| THEN |
| InternalError ('constructor type must be an array') |
| ELSE |
| PushCard(i) ; |
| j := PopIntegerTree() ; |
| e := arrayValues ; |
| WHILE e#NIL DO |
| PushValue(e^.by) ; |
| PushIntegerTree(j) ; |
| IF GreEqu(tokenno) |
| THEN |
| RETURN( e^.element ) |
| END ; |
| PushIntegerTree(j) ; |
| ConvertToInt ; |
| PushValue(e^.by) ; |
| ConvertToInt ; |
| Sub ; |
| j := PopIntegerTree() ; |
| e := e^.next |
| END ; |
| IF e=NIL |
| THEN |
| IF IsArray(SkipType(constructorType)) AND (GetType(SkipType(constructorType))=Char) |
| THEN |
| RETURN MakeConstLit (tokenno, MakeKey('0'), Char) |
| ELSE |
| MetaErrorT2 (tokenno, |
| 'the {%1EN} element does not exist in the {%2ad} array declaration used by the compound literal', i, constructorType) ; |
| END |
| END |
| END |
| END |
| END ; |
| RETURN NulSym |
| END GetConstructorElement ; |
| |
| |
| (* |
| IsString - returns TRUE if sym is an ARRAY [..] OF CHAR |
| *) |
| |
| PROCEDURE IsString (sym: CARDINAL) : BOOLEAN ; |
| BEGIN |
| RETURN (IsArray(sym) AND (SkipType(GetType(sym))=Char)) OR |
| IsConstString(sym) OR |
| (IsConst(sym) AND (SkipType(GetType(sym))=Char)) |
| END IsString ; |
| |
| |
| (* |
| StringFitsArray - |
| *) |
| |
| PROCEDURE StringFitsArray (arrayType, el: CARDINAL; tokenno: CARDINAL) : BOOLEAN ; |
| VAR |
| location: location_t ; |
| BEGIN |
| location := TokenToLocation(tokenno) ; |
| PushIntegerTree(BuildNumberOfArrayElements(location, Mod2Gcc(arrayType))) ; |
| IF IsConstString(el) |
| THEN |
| PushCard(GetStringLength(tokenno, el)) |
| ELSIF IsConst(el) AND (SkipType(GetType(el))=Char) AND IsValueSolved(el) |
| THEN |
| PushCard(1) |
| ELSE |
| PushCard(0) ; |
| MetaError1 ('cannot build a string using {%1Ead}', el) |
| END ; |
| RETURN GreEqu(tokenno) |
| END StringFitsArray ; |
| |
| |
| (* |
| GetArrayLimits - |
| *) |
| |
| PROCEDURE GetArrayLimits (array: CARDINAL; VAR low, high: CARDINAL) ; |
| VAR |
| Subscript, |
| Subrange : CARDINAL ; |
| BEGIN |
| Subscript := GetArraySubscript(array) ; |
| Subrange := SkipType(GetType(Subscript)) ; |
| IF IsEnumeration(Subrange) |
| THEN |
| GetBaseTypeMinMax(Subrange, low, high) |
| ELSE |
| GetSubrange(Subrange, high, low) |
| END |
| END GetArrayLimits ; |
| |
| |
| (* |
| InitialiseArrayOfCharWithString - |
| *) |
| |
| PROCEDURE InitialiseArrayOfCharWithString (tokenno: CARDINAL; cons: ADDRESS; |
| el, baseType, arrayType: CARDINAL) : tree ; |
| VAR |
| isChar : BOOLEAN ; |
| s, letter: String ; |
| i, l : CARDINAL ; |
| high, low: CARDINAL ; |
| value, |
| indice : tree ; |
| location : location_t ; |
| BEGIN |
| location := TokenToLocation(tokenno) ; |
| GetArrayLimits(baseType, low, high) ; |
| l := 0 ; |
| s := NIL ; |
| IF IsConstString(el) |
| THEN |
| isChar := FALSE ; |
| s := InitStringCharStar(KeyToCharStar(GetString(el))) ; |
| l := GetStringLength(tokenno, el) |
| ELSIF IsConst(el) AND (SkipType(GetType(el))=Char) AND IsValueSolved(el) |
| THEN |
| isChar := TRUE |
| ELSE |
| MetaError1 ('cannot build a string using {%1Ead}', el) ; |
| isChar := FALSE |
| END ; |
| i := 0 ; |
| REPEAT |
| PushValue(low) ; |
| PushCard(i) ; |
| Addn ; |
| indice := PopIntegerTree() ; |
| letter := NIL ; |
| IF isChar |
| THEN |
| isChar := FALSE ; |
| PushValue(el) ; |
| value := PopIntegerTree() |
| ELSIF i<l |
| THEN |
| IF i+1<l |
| THEN |
| letter := Slice(s, i, i+1) |
| ELSE |
| letter := Slice(s, i, 0) |
| END ; |
| value := BuildCharConstant(location, string(letter)) ; |
| ELSE |
| letter := InitStringChar(nul) ; |
| value := BuildCharConstant(location, string(letter)) |
| END ; |
| value := ConvertConstantAndCheck(location, Mod2Gcc(arrayType), value) ; |
| letter := KillString(letter) ; |
| BuildArrayConstructorElement(cons, value, indice) ; |
| PushValue(low) ; |
| PushCard(i) ; |
| Addn ; |
| PushValue(high) ; |
| INC(i) |
| UNTIL GreEqu(tokenno) ; |
| s := KillString(s) ; |
| IF NOT StringFitsArray(baseType, el, tokenno) |
| THEN |
| MetaError2 ('string {%1Ea} is too large to fit into array {%2ad}', el, baseType) |
| END ; |
| (* |
| IF v#NIL |
| THEN |
| el := GetConstructorElement(tokenno, v, 2) ; |
| IF el#NulSym |
| THEN |
| MetaError1('not allowed to have multiple strings to initialise an array of characters {%1Ua}', el) |
| END |
| END ; |
| *) |
| RETURN( BuildEndArrayConstructor(cons) ) |
| END InitialiseArrayOfCharWithString ; |
| |
| |
| (* |
| CheckElementString - |
| *) |
| |
| PROCEDURE CheckElementString (el, arrayType: CARDINAL; tokenno: CARDINAL) : tree ; |
| VAR |
| cons: ADDRESS ; |
| BEGIN |
| IF IsString(arrayType) AND IsString(el) |
| THEN |
| cons := BuildStartArrayConstructor(Mod2Gcc(arrayType)) ; |
| RETURN( InitialiseArrayOfCharWithString(tokenno, cons, el, arrayType, SkipType(GetType(arrayType))) ) |
| ELSE |
| RETURN( Mod2Gcc(el) ) |
| END |
| END CheckElementString ; |
| |
| |
| (* |
| InitialiseArrayWith - |
| *) |
| |
| PROCEDURE InitialiseArrayWith (tokenno: CARDINAL; cons: ADDRESS; |
| v: PtrToValue; el, high, low, arrayType: CARDINAL) : tree ; |
| VAR |
| location: location_t ; |
| i : CARDINAL ; |
| indice, |
| value : tree ; |
| BEGIN |
| location := TokenToLocation (tokenno) ; |
| i := 0 ; |
| WHILE el#NulSym DO |
| PushValue (low) ; |
| ConvertToInt ; |
| PushInt (i) ; |
| Addn ; |
| indice := PopIntegerTree () ; |
| value := CheckElementString (el, arrayType, tokenno) ; |
| IF value = NIL |
| THEN |
| MetaErrorT0 (tokenno, '{%W}too few characters found when trying to construct a compound literal array') ; |
| value := GetCardinalZero (location) |
| END ; |
| value := ConvertConstantAndCheck (location, Mod2Gcc (arrayType), value) ; |
| BuildArrayConstructorElement (cons, value, indice) ; |
| PushValue (low) ; |
| ConvertToInt ; |
| PushInt (i) ; |
| Addn ; |
| PushValue (high) ; |
| ConvertToInt ; |
| IF GreEqu (tokenno) |
| THEN |
| RETURN BuildEndArrayConstructor (cons) |
| END ; |
| INC (i) ; |
| el := GetConstructorElement (tokenno, v, i+1) |
| END ; |
| RETURN BuildEndArrayConstructor (cons) |
| END InitialiseArrayWith ; |
| |
| |
| (* |
| CheckGetCharFromString - return TRUE if a char from the position arrayIndex in the list of |
| constDecl elements can be extracted. The character is returned |
| in value. |
| *) |
| |
| PROCEDURE CheckGetCharFromString (location: location_t; |
| tokenno: CARDINAL ; |
| constDecl: PtrToValue; |
| consType: CARDINAL ; |
| arrayIndex: CARDINAL; |
| VAR value: tree) : BOOLEAN ; |
| VAR |
| elementIndex: CARDINAL ; |
| element : CARDINAL ; |
| offset, |
| totalLength : CARDINAL ; |
| key : Name ; |
| BEGIN |
| totalLength := 0 ; |
| elementIndex := 1 ; |
| REPEAT |
| element := GetConstructorElement (tokenno, constDecl, elementIndex) ; |
| offset := totalLength ; |
| IF IsConstString (element) |
| THEN |
| INC (totalLength, GetStringLength (tokenno, element)) ; |
| IF totalLength > arrayIndex |
| THEN |
| key := GetString (element) ; |
| DEC (arrayIndex, offset) ; |
| value := BuildCharConstantChar (location, CharKey (key, arrayIndex)) ; |
| RETURN TRUE |
| END |
| ELSIF IsConst (element) AND (SkipType (GetType (element)) = Char) AND IsValueSolved (element) |
| THEN |
| INC (totalLength) ; |
| IF totalLength > arrayIndex |
| THEN |
| PushValue (element) ; |
| value := ConvertConstantAndCheck (location, GetM2CharType (), PopIntegerTree ()) ; |
| RETURN TRUE |
| END |
| ELSE |
| INC (totalLength) ; |
| IF totalLength > arrayIndex |
| THEN |
| MetaErrorT3 (tokenno, |
| 'expecting {%kCHAR} datatype and not {%1Ea} a {%1tad} in the {%2N} component of the {%3a} {%3d}', |
| element, arrayIndex, consType) ; |
| value := GetCardinalZero (location) ; |
| RETURN FALSE |
| END |
| END ; |
| INC (elementIndex) |
| UNTIL element = NulSym ; |
| value := GetCardinalZero (location) ; |
| MetaErrorT2 (tokenno, |
| 'unable to obtain a {%kCHAR} at the {%1EN} position in {%2ad}', |
| arrayIndex, consType) ; |
| RETURN FALSE |
| END CheckGetCharFromString ; |
| |
| |
| (* |
| InitialiseArrayOfCharWith - |
| *) |
| |
| PROCEDURE InitialiseArrayOfCharWith (tokenno: CARDINAL; cons: ADDRESS; |
| constDecl: PtrToValue; |
| el, high, low, consType, arrayType: CARDINAL) : tree ; |
| VAR |
| location : location_t ; |
| arrayIndex: CARDINAL ; (* arrayIndex is the char position index of the final string. *) |
| indice, |
| value : tree ; |
| BEGIN |
| location := TokenToLocation (tokenno) ; |
| arrayIndex := 0 ; |
| WHILE el#NulSym DO |
| PushValue (low) ; |
| ConvertToInt ; |
| PushInt (arrayIndex) ; |
| Addn ; |
| indice := PopIntegerTree () ; |
| IF NOT CheckGetCharFromString (location, tokenno, constDecl, consType, arrayIndex, value) |
| THEN |
| (* |
| MetaErrorT2 (tokenno, |
| 'unable to obtain a {%kCHAR} at the {%1EN} position in {%2ad}', |
| arrayIndex, consType) ; |
| *) |
| END ; |
| value := ConvertConstantAndCheck (location, Mod2Gcc (arrayType), value) ; |
| BuildArrayConstructorElement (cons, value, indice) ; |
| PushValue (low) ; |
| ConvertToInt ; |
| PushInt (arrayIndex) ; |
| Addn ; |
| PushValue (high) ; |
| ConvertToInt ; |
| IF GreEqu (tokenno) |
| THEN |
| RETURN BuildEndArrayConstructor (cons) |
| END ; |
| INC (arrayIndex) |
| END ; |
| RETURN BuildEndArrayConstructor (cons) |
| END InitialiseArrayOfCharWith ; |
| |
| |
| (* |
| ConstructArrayConstant - builds a struct initializer, as defined by, v. |
| *) |
| |
| PROCEDURE ConstructArrayConstant (tokenno: CARDINAL; v: PtrToValue) : tree ; |
| VAR |
| n1, n2 : Name ; |
| el1, el2, |
| baseType, |
| arrayType, |
| high, low : CARDINAL ; |
| cons : ADDRESS ; |
| BEGIN |
| WITH v^ DO |
| IF constructorType=NulSym |
| THEN |
| InternalError ('array type must be known in order to generate a constant') |
| ELSE |
| baseType := SkipType(constructorType) ; |
| IF Debugging |
| THEN |
| n1 := GetSymName(constructorType) ; |
| n2 := GetSymName(baseType) ; |
| printf2 ('ConstructArrayConstant of type %a and baseType %a\n', n1, n2) |
| END ; |
| cons := BuildStartArrayConstructor(Mod2Gcc(baseType)) ; |
| |
| GetArrayLimits(baseType, low, high) ; |
| arrayType := GetType(baseType) ; |
| |
| el1 := GetConstructorElement(tokenno, v, 1) ; |
| el2 := GetConstructorElement(tokenno, v, 2) ; |
| IF (el2 = NulSym) AND IsString(baseType) AND IsString(el1) |
| THEN |
| (* constructorType is ARRAY [low..high] OF CHAR and using a string to initialise it *) |
| RETURN InitialiseArrayOfCharWithString (tokenno, cons, el1, baseType, arrayType) |
| ELSIF SkipType(arrayType)=Char |
| THEN |
| RETURN InitialiseArrayOfCharWith (tokenno, cons, v, el1, high, low, baseType, arrayType) |
| ELSE |
| RETURN InitialiseArrayWith (tokenno, cons, v, el1, high, low, arrayType) |
| END |
| END |
| END |
| END ConstructArrayConstant ; |
| |
| |
| (* |
| BuildRange - returns a integer sized constant which represents the |
| value {e1..e2}. |
| *) |
| |
| PROCEDURE BuildRange (tokenno: CARDINAL; e1, e2: tree) : tree ; |
| VAR |
| c, i, t : tree ; |
| location: location_t ; |
| BEGIN |
| location := TokenToLocation(tokenno) ; |
| PushIntegerTree(e1) ; |
| PushIntegerTree(e2) ; |
| IF Gre(tokenno) |
| THEN |
| c := e1 ; |
| e1 := e2 ; |
| e2 := c |
| END ; |
| t := tree(NIL) ; |
| PushIntegerTree(e1) ; |
| i := PopIntegerTree() ; |
| REPEAT |
| IF t=tree(NIL) |
| THEN |
| t := BuildLSL(location, GetWordOne(location), ToWord(location, i), FALSE) |
| ELSE |
| t := BuildLogicalOr(location, t, BuildLSL(location, GetWordOne(location), ToWord(location, i), FALSE), FALSE) |
| END ; |
| PushIntegerTree(i) ; |
| PushIntegerTree(GetIntegerOne(location)) ; |
| Addn ; |
| i := PopIntegerTree() ; |
| PushIntegerTree(i) ; |
| PushIntegerTree(e2) ; |
| UNTIL Gre(tokenno) ; |
| RETURN( t ) |
| END BuildRange ; |
| |
| |
| (* |
| BuildBitset - given a set, v, construct the bitmask for its |
| constant value which lie in the range low..high. |
| *) |
| |
| PROCEDURE BuildBitset (tokenno: CARDINAL; |
| v: PtrToValue; low, high: tree) : tree ; |
| VAR |
| tl, th, |
| t : tree ; |
| n : CARDINAL ; |
| r1, r2 : CARDINAL ; |
| location: location_t ; |
| BEGIN |
| location := TokenToLocation(tokenno) ; |
| low := ToInteger(location, low) ; |
| high := ToInteger(location, high) ; |
| n := 1 ; |
| t := GetCardinalZero(location) ; |
| WHILE GetRange(v, n, r1, r2) DO |
| PushValue(r1) ; |
| tl := ToInteger(location, PopIntegerTree()) ; |
| PushValue(r2) ; |
| th := ToInteger(location, PopIntegerTree()) ; |
| IF IsIntersectionTree(tokenno, tl, th, low, high) |
| THEN |
| tl := ToCardinal(location, SubTree(MaxTree(tokenno, tl, low), low)) ; |
| th := ToCardinal(location, SubTree(MinTree(tokenno, th, high), low)) ; |
| t := BuildLogicalOr(location, t, BuildRange(tokenno, tl, th), FALSE) |
| END ; |
| INC(n) |
| END ; |
| RETURN( ToBitset(location, t) ) |
| END BuildBitset ; |
| |
| |
| (* |
| IsValueAndTreeKnown - returns TRUE if the value is known and the gcc tree |
| is defined. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | Op1 | <- Ptr |
| |------------| +------------+ |
| *) |
| |
| PROCEDURE IsValueAndTreeKnown () : BOOLEAN ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := Pop() ; |
| IF v#NIL |
| THEN |
| WITH v^ DO |
| IF solved |
| THEN |
| CASE type OF |
| |
| integer, |
| real, |
| complex: IF numberValue=NIL |
| THEN |
| Dispose(v) ; |
| RETURN( FALSE ) |
| END |
| ELSE |
| END |
| ELSE |
| Dispose(v) ; |
| RETURN( FALSE ) |
| END |
| END ; |
| Dispose(v) |
| END ; |
| RETURN( TRUE ) |
| END IsValueAndTreeKnown ; |
| |
| |
| (* |
| CheckOverflow - tests to see whether the tree, t, has caused |
| an overflow error and if so it generates an |
| error message. |
| *) |
| |
| PROCEDURE CheckOverflow (tokenno: CARDINAL; t: tree) ; |
| BEGIN |
| IF TreeOverflow (t) |
| THEN |
| MetaErrorT0 (tokenno, 'constant overflow error') ; |
| FlushErrors |
| END |
| END CheckOverflow ; |
| |
| |
| (* |
| CheckOrResetOverflow - tests to see whether the tree, t, has caused |
| an overflow error and if so it generates an |
| error message. |
| *) |
| |
| PROCEDURE CheckOrResetOverflow (tokenno: CARDINAL; t: tree; check: BOOLEAN) ; |
| BEGIN |
| IF check |
| THEN |
| CheckOverflow (tokenno, t) |
| ELSE |
| t := RemoveOverflow (t) |
| END |
| END CheckOrResetOverflow ; |
| |
| |
| (* |
| PushGCCArrayTree - pushes a gcc tree value onto the ALU stack. |
| *) |
| |
| PROCEDURE PushGCCArrayTree (gcc: tree; t: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := New() ; |
| WITH v^ DO |
| constructorType := t ; |
| type := array ; |
| numberValue := gcc ; |
| arrayValues := NIL ; |
| areAllConstants := TRUE ; |
| solved := TRUE |
| END ; |
| Push(v) |
| END PushGCCArrayTree ; |
| |
| |
| (* |
| PushGCCSetTree - pushes a gcc tree value onto the ALU stack. |
| *) |
| |
| PROCEDURE PushGCCSetTree (gcc: tree; t: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := New() ; |
| WITH v^ DO |
| constructorType := t ; |
| type := set ; |
| numberValue := gcc ; |
| setValue := NIL ; |
| areAllConstants := TRUE ; |
| solved := TRUE |
| END ; |
| Push(v) |
| END PushGCCSetTree ; |
| |
| |
| (* |
| PushGCCRecordTree - pushes a gcc tree value onto the ALU stack. |
| *) |
| |
| PROCEDURE PushGCCRecordTree (gcc: tree; t: CARDINAL) ; |
| VAR |
| v: PtrToValue ; |
| BEGIN |
| v := New() ; |
| WITH v^ DO |
| constructorType := t ; |
| type := record ; |
| numberValue := gcc ; |
| fieldValues := NIL ; |
| areAllConstants := TRUE ; |
| solved := TRUE |
| END ; |
| Push(v) |
| END PushGCCRecordTree ; |
| |
| |
| (* |
| PushTypeOfTree - pushes tree, gcc, to the stack and records the |
| front end type. |
| *) |
| |
| PROCEDURE PushTypeOfTree (sym: CARDINAL; gcc: tree) ; |
| VAR |
| t: CARDINAL ; |
| BEGIN |
| t := SkipType(GetType(sym)) ; |
| IF t=NulSym |
| THEN |
| PushIntegerTree(gcc) |
| ELSIF IsComplexType(t) |
| THEN |
| PushComplexTree(gcc) |
| ELSIF IsArray(t) |
| THEN |
| PushGCCArrayTree(gcc, t) |
| ELSIF IsSet(t) |
| THEN |
| PushGCCSetTree(gcc, t) |
| ELSIF IsRecord(t) |
| THEN |
| PushGCCRecordTree(gcc, t) |
| ELSIF IsRealType(t) |
| THEN |
| PushRealTree(gcc) |
| ELSE |
| PushIntegerTree(gcc) |
| END |
| END PushTypeOfTree ; |
| |
| |
| (* |
| Init - initialises the stack and the free list. |
| *) |
| |
| PROCEDURE Init ; |
| BEGIN |
| FreeList := NIL ; |
| TopOfStack := NIL ; |
| RangeFreeList := NIL ; |
| FieldFreeList := NIL ; |
| ElementFreeList := NIL |
| END Init ; |
| |
| |
| BEGIN |
| Init |
| END M2ALU. |
| (* |
| * Local variables: |
| * compile-command: "gm2 -c -g -I.:../gm2-libs:../gm2-libs-ch:../gm2-libiberty/ M2ALU.mod" |
| * End: |
| *) |