123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080 |
- MODULE FoxAssembler; (** AUTHOR "fof"; PURPOSE "Oberon Assembler: Generic Part"; **)
- (* (c) fof ETH Zürich, 2009 *)
- IMPORT Streams, Strings, Diagnostics,D := Debugging, Commands, BinaryCode := FoxBinaryCode, SyntaxTree := FoxSyntaxTree, Global := FoxGlobal,
- IntermediateCode := FoxIntermediateCode, Sections := FoxSections, Scanner := FoxScanner, Basic := FoxBasic, SYSTEM, ObjectFile;
- CONST
- Trace* = FALSE; (* debugging output *)
- MaxOperands* = 3;
- (*
- currently there is conceptual support for one-pass assembly with a fixup mechanism for section-local references
- disadvantages of one-pass assembly:
- - expressions with labels would not work
- - fixup mechanism complicated and not generic
- *)
- MaxPasses* = 2;
- ConstantInteger* = 0;
- ConstantFloat* = 1;
- Fixup* = 2;
- Offset* = 3;
- ConstantIntegerOrOffset* = {ConstantInteger, Offset};
- TYPE
- OperandString=ARRAY 256 OF CHAR;
- Position= Basic.Position;
- FixupElement=POINTER TO RECORD
- fixup: BinaryCode.Fixup; next: FixupElement;
- END;
- NamedLabel*= OBJECT
- VAR
- section: IntermediateCode.Section;
- offset, displacement: LONGINT; (* in contrast to offset, displacement will be reset each round of assembling. This is to make sure that GetFixup generates the right displacement in the fixup *)
- name-: Scanner.IdentifierString;
- nextNamedLabel-: NamedLabel;
- fixupList: FixupElement;
- PROCEDURE &InitNamedLabel(section: IntermediateCode.Section; CONST name: ARRAY OF CHAR);
- BEGIN
- fixupList := NIL;
- SELF.offset := 0; (* must be zero to be able to track local displacement *)
- SELF.section := section;
- COPY(name,SELF.name);
- nextNamedLabel := NIL;
- END InitNamedLabel;
- PROCEDURE GetFixup(): BinaryCode.Fixup;
- VAR fixup: BinaryCode.Fixup; element: FixupElement; identifier: ObjectFile.Identifier;
- BEGIN
- identifier.name := section.name;
- fixup := BinaryCode.NewFixup(BinaryCode.Absolute,0,identifier,0,displacement,0,NIL);
- NEW(element); element.fixup := fixup; element.next := fixupList; fixupList := element;
- RETURN fixup;
- END GetFixup;
- PROCEDURE ResetDisplacements;
- VAR element: FixupElement;
- BEGIN
- displacement := 0;
- element := fixupList;
- WHILE element # NIL DO
- element.fixup.SetSymbol(section.name,0,0,0);
- element := element.next;
- END;
- END ResetDisplacements;
- PROCEDURE SetOffset*(ofs: LONGINT);
- VAR element: FixupElement;
- BEGIN
- SELF.offset := ofs;
- displacement := ofs;
- element := fixupList;
- WHILE element # NIL DO
- element.fixup.SetSymbol(section.name,0,0,element.fixup.displacement (* must be here to take into account modifications of code emission *) +displacement);
- element := element.next;
- END;
- END SetOffset;
- END NamedLabel;
- NamedLabelList*=OBJECT
- VAR first-,last-: NamedLabel;
- PROCEDURE & InitNamedLabelList;
- BEGIN first := NIL; last := NIL
- END InitNamedLabelList;
- PROCEDURE Add*(n: NamedLabel);
- BEGIN
- IF first = NIL THEN first := n ELSE last.nextNamedLabel := n; last.nextNamedLabel := n; END; last := n;
- END Add;
- PROCEDURE ResetDisplacements;
- VAR label: NamedLabel;
- BEGIN
- label := first;
- WHILE label # NIL DO label.ResetDisplacements; label := label.nextNamedLabel END;
- END ResetDisplacements;
- PROCEDURE Find*(CONST name: ARRAY OF CHAR): NamedLabel;
- VAR label: NamedLabel;
- BEGIN
- label := first;
- WHILE (label # NIL) & (label.name # name) DO
- label := label.nextNamedLabel;
- END;
- RETURN label
- END Find;
- END NamedLabelList;
- Result*= RECORD
- type*: INTEGER; (* ConstantInteger, ConstantFloat, Fixup, Offset *)
- sizeInBits*: INTEGER;
- value*: LONGINT; (*! implementation restriction: operations between hugeints do not yet work *)
- valueR*: LONGREAL;
- fixup*: BinaryCode.Fixup;
- END;
- NamedResult*=POINTER TO RECORD (Result)
- name: Scanner.IdentifierString;
- nextResult: NamedResult;
- END;
- NamedResultList*=OBJECT
- VAR first, last: NamedResult; number: LONGINT;
- PROCEDURE & InitNamedResultList;
- BEGIN first := NIL; last := NIL; number := 0;
- END InitNamedResultList;
- PROCEDURE Add*(n: NamedResult);
- BEGIN
- IF first = NIL THEN first := n ELSE last.nextResult := n END; last := n; INC(number);
- END Add;
- PROCEDURE Find*(CONST name: ARRAY OF CHAR): NamedResult;
- VAR result: NamedResult;
- BEGIN
- result := first;
- WHILE (result # NIL) & (result.name # name) DO
- result := result.nextResult;
- END;
- RETURN result
- END Find;
- END NamedResultList;
- Assembler*= OBJECT
- VAR
- diagnostics: Diagnostics.Diagnostics;
- error-: BOOLEAN;
- errorPosition-: Position;
- symbol-: Scanner.Symbol;
- scanner: Scanner.AssemblerScanner;
- orgOffset: LONGINT;
- section-: IntermediateCode.Section;
- code: BinaryCode.Section;
- labels: NamedLabelList;
- results: NamedResultList;
- scope: SyntaxTree.Scope;
- module: Sections.Module;
- pass-: LONGINT;
- PROCEDURE &Init*(diagnostics: Diagnostics.Diagnostics);
- BEGIN
- SELF.diagnostics := diagnostics; errorPosition := Basic.invalidPosition; orgOffset := 0;
- END Init;
- PROCEDURE SetContext(CONST context: Scanner.Context);
- BEGIN
- scanner.SetContext(context); NextSymbol;
- END SetContext;
- PROCEDURE Error*(pos: SyntaxTree.Position; CONST msg: ARRAY OF CHAR);
- BEGIN
- error := TRUE;
- IF diagnostics # NIL THEN
- diagnostics.Error(scanner.source^,pos.start,Diagnostics.Invalid,msg);
- END;
- END Error;
- PROCEDURE ErrorSS*(pos: SyntaxTree.Position; CONST s1,s2: ARRAY OF CHAR);
- VAR msg: Basic.MessageString;
- BEGIN COPY(s1,msg); Strings.Append(msg,s2); Error(pos, msg);
- END ErrorSS;
- PROCEDURE NextSymbol*;
- BEGIN error := error OR ~scanner.GetNextSymbol(symbol); errorPosition := symbol.position;
- END NextSymbol;
- PROCEDURE ThisToken*(x: LONGINT): BOOLEAN;
- BEGIN
- IF ~error & (symbol.token = x) THEN NextSymbol; RETURN TRUE ELSE RETURN FALSE END;
- END ThisToken;
- PROCEDURE GetIdentifier*(VAR pos: Position; VAR identifier: ARRAY OF CHAR): BOOLEAN;
- BEGIN
- pos := symbol.position;
- IF symbol.token # Scanner.Identifier THEN RETURN FALSE
- ELSE COPY(symbol.identifierString,identifier); NextSymbol; RETURN TRUE
- END;
- END GetIdentifier;
- PROCEDURE ThisIdentifier*(CONST this: ARRAY OF CHAR): BOOLEAN;
- BEGIN
- IF ~error & (symbol.token = Scanner.Identifier) & (this = symbol.identifierString) THEN NextSymbol; RETURN TRUE ELSE RETURN FALSE END;
- END ThisIdentifier;
- PROCEDURE ExpectIdentifier*(VAR pos: Position; VAR identifier: ARRAY OF CHAR): BOOLEAN;
- BEGIN
- IF ~GetIdentifier(pos,identifier)THEN Error(errorPosition,"identifier expected"); RETURN FALSE
- ELSE RETURN TRUE
- END;
- END ExpectIdentifier;
- PROCEDURE ExpectToken*(x: LONGINT): BOOLEAN;
- VAR s: Basic.MessageString;
- BEGIN
- IF ThisToken(x) THEN RETURN TRUE
- ELSE
- s := "expected token "; Strings.Append(s,Scanner.tokens[x]); Strings.Append(s," but got "); Strings.Append(s,Scanner.tokens[symbol.token]);
- Error(errorPosition,s);RETURN FALSE
- END;
- END ExpectToken;
- PROCEDURE ExpectConstantInteger*(VAR x: Result; critical: BOOLEAN): BOOLEAN;
- VAR result: Result;
- BEGIN
- IF ~Expression(result,critical) OR (result.type # ConstantInteger) THEN
- result.value := 0;
- IF critical THEN Error(errorPosition,"constant integer expected") END;
- RETURN ~critical
- ELSE RETURN TRUE
- END
- END ExpectConstantInteger;
- PROCEDURE Section;
- VAR sectionType: Scanner.IdentifierString; pos: Position;
- BEGIN
- IF ExpectToken(Scanner.Period) THEN
- IF ExpectIdentifier(pos,sectionType) THEN
- IF sectionType = "data" THEN
- IF Trace THEN D.String("data section"); D.Ln END;
- (*! generate section here, if allowed *)
- ELSIF sectionType = "code" THEN
- IF Trace THEN D.String("code section"); D.Ln END;
- (*! generate section here, if allowed *)
- ELSE Error(pos,"expected data or code");
- END;
- END;
- END;
- END Section;
- PROCEDURE DefineLabel(pos: Position; CONST name: ARRAY OF CHAR);
- VAR label: NamedLabel;
- BEGIN
- IF Trace THEN D.String("define label: "); D.String(name); D.Ln END;
- IF labels.Find(name) # NIL THEN
- Error(pos,"multiply declared identifier")
- ELSE
- NEW(label,section,name);
- labels.Add(label);
- ASSERT(labels.Find(name) =label);
- END;
- END DefineLabel;
- PROCEDURE SetLabel(pos: Position; CONST name: ARRAY OF CHAR);
- VAR label: NamedLabel;
- BEGIN
- IF Trace THEN D.String("set label: "); D.String(name); D.String(" "); D.Int(code.pc,1); D.Ln END;
- label := labels.Find(name);
- label.SetOffset(code.pc);
- END SetLabel;
- PROCEDURE CopyResult(CONST from: Result; VAR to: Result);
- BEGIN
- to.type := from.type;
- to.sizeInBits := from.sizeInBits;
- to.value := from.value;
- to.valueR := from.valueR;
- to.fixup := from.fixup;
- END CopyResult;
- PROCEDURE DefineResult(pos: Position; CONST name: ARRAY OF CHAR; CONST r: Result);
- VAR result: NamedResult;
- BEGIN
- IF Trace THEN D.String("define result: "); D.String(name); D.Ln END;
- IF results.Find(name) # NIL THEN
- Error(pos,"multiply declared identifier")
- ELSE
- NEW(result); COPY(name,result.name);
- CopyResult(r,result^);
- results.Add(result);
- ASSERT(results.Find(name) =result);
- END;
- END DefineResult;
- PROCEDURE SetResult(CONST name: ARRAY OF CHAR; CONST r: Result);
- VAR result: NamedResult;
- BEGIN
- IF Trace THEN D.String("define result: "); D.String(name); D.Ln END;
- result := results.Find(name);
- CopyResult(r,result^);
- END SetResult;
- PROCEDURE SymbolInScope(CONST ident: ARRAY OF CHAR): SyntaxTree.Symbol;
- VAR sym: SyntaxTree.Symbol; localScope: SyntaxTree.Scope; identifier: SyntaxTree.Identifier;
- CONST Trace=FALSE;
- BEGIN
- IF scope = NIL THEN RETURN NIL END;
- localScope := scope;
- identifier := SyntaxTree.NewIdentifier(ident);
- IF Trace THEN D.String("GetScopeSymbol:"); D.String(ident); D.Ln; END;
- WHILE (sym = NIL) & (localScope # NIL) DO
- sym := localScope.FindSymbol(identifier);
- localScope := localScope.outerScope
- END;
- IF (sym # NIL) & (sym IS SyntaxTree.Import) THEN
- NextSymbol;
- IF ExpectToken(Scanner.Period) & (symbol.token = Scanner.Identifier) THEN
- identifier := SyntaxTree.NewIdentifier(symbol.identifierString);
- IF Trace THEN D.String("GetScopeSymbol :"); D.String(symbol.identifierString); D.Ln; END;
- localScope := sym(SyntaxTree.Import).module.moduleScope;
- sym := NIL;
- WHILE (sym = NIL) & (localScope # NIL) DO
- sym := localScope.FindSymbol(identifier);
- IF (sym # NIL) & (sym.access * SyntaxTree.Public = {}) THEN sym := NIL END;
- localScope := localScope.outerScope
- END;
- ELSE RETURN NIL
- END;
- END;
- IF Trace THEN IF sym = NIL THEN D.String("not found") ELSE D.String("found"); END; D.Ln; END;
- RETURN sym
- END SymbolInScope;
- PROCEDURE ConstantSymbol(pos: Position; constant: SyntaxTree.Constant; VAR result: Result): BOOLEAN;
- BEGIN
- IF constant.type.resolved IS SyntaxTree.CharacterType THEN
- result.value := ORD(constant.value.resolved(SyntaxTree.CharacterValue).value);
- result.valueR := result.value;
- result.type := ConstantInteger;
- ELSIF constant.type.resolved IS SyntaxTree.IntegerType THEN
- result.value := constant.value.resolved(SyntaxTree.IntegerValue).value;
- result.valueR := result.value;
- result.type := ConstantInteger;
- ELSIF constant.type.resolved IS SyntaxTree.FloatType THEN
- result.valueR := constant.value.resolved(SyntaxTree.RealValue).value;
- result.type := ConstantFloat;
- ELSE
- Error(pos,"incompatible constant");
- RETURN FALSE;
- END;
- result.sizeInBits := SHORT(module.system.SizeOf(constant.type));
- RETURN TRUE
- END ConstantSymbol;
- PROCEDURE GetFingerprint(symbol: SyntaxTree.Symbol): LONGINT;
- BEGIN
- IF (symbol # NIL) THEN RETURN symbol.fingerprint.shallow END;
- END GetFingerprint;
- PROCEDURE NonConstantSymbol(pos: Position; symbol: SyntaxTree.Symbol; VAR result: Result): BOOLEAN;
- VAR
- name: Basic.SegmentedName; moduleScope: SyntaxTree.Scope; fixupSection: IntermediateCode.Section;
- fixupPatternList: ObjectFile.FixupPatterns; identifier: ObjectFile.Identifier;
- BEGIN
- IF scope = NIL THEN RETURN FALSE END;
- moduleScope := scope.ownerModule.moduleScope;
- Global.GetSymbolSegmentedName(symbol,name);
- identifier.name := name;
- identifier.fingerprint := GetFingerprint(symbol);
- IF symbol.scope IS SyntaxTree.ModuleScope THEN (* symbol in module scope *)
- IF symbol IS SyntaxTree.Variable THEN (* global variable *)
- result.type := Fixup;
- result.sizeInBits := SHORT(module.system.SizeOf(symbol.type));
- (* generic fixup pattern list for generic implementation of data instruction etc. -- otherwise replaced during encoding *)
- NEW(fixupPatternList, 1);
- fixupPatternList[0].bits := result.sizeInBits;
- fixupPatternList[0].offset := 0;
- result.fixup := BinaryCode.NewFixup(BinaryCode.Absolute, 0, identifier, 0, 0, 0, fixupPatternList);
- ELSIF symbol IS SyntaxTree.Procedure THEN (* procedure *)
- IF symbol(SyntaxTree.Procedure).isInline THEN
- Error(pos,"forbidden reference to inline procedure"); RETURN FALSE
- ELSE
- result.type := Fixup;
- result.sizeInBits := SHORT(module.system.SizeOf(symbol.type));
- (* generic fixup pattern list for generic implementation of data instruction etc. -- otherwise replaced during encoding *)
- NEW(fixupPatternList, 1);
- fixupPatternList[0].bits := result.sizeInBits;
- fixupPatternList[0].offset := 0;
- result.fixup := BinaryCode.NewFixup(BinaryCode.Absolute, 0, identifier, 0, 0, 0, fixupPatternList);
- END;
- ELSE HALT(100);
- END;
- ELSIF symbol.scope IS SyntaxTree.ProcedureScope THEN (* symbol in procedure (local) scope *)
- IF symbol.scope # scope THEN
- Error(pos,"local symbol not in current scope");
- ELSE
- RETURN FALSE;
- IF (symbol IS SyntaxTree.Variable) OR (symbol IS SyntaxTree.Parameter) THEN
- result.type := Offset;
- result.value := symbol.offsetInBits DIV module.system.dataUnit;
- ASSERT(symbol.offsetInBits MOD module.system.dataUnit = 0);
- result.sizeInBits := SHORT(module.system.SizeOf(symbol.type));
- ELSE Error(pos,"forbidden symbol in local scope");
- END;
- END
- ELSIF symbol.scope IS SyntaxTree.RecordScope THEN (* symbol in record scope *)
- ELSE Error(pos,"symbol in forbidden scope"); RETURN FALSE
- END;
- RETURN TRUE
- END NonConstantSymbol;
- PROCEDURE GetNonConstant*(pos: Position; CONST ident: ARRAY OF CHAR; VAR result: Result): BOOLEAN;
- VAR symbol: SyntaxTree.Symbol; namedLabel: NamedLabel;
- name: Basic.SegmentedName;fixupPatternList: ObjectFile.FixupPatterns;
- string: ARRAY 256 OF CHAR;
- identifier: ObjectFile.Identifier;
- BEGIN
- namedLabel := labels.Find(ident);
- IF (namedLabel # NIL) THEN
- result.type := Fixup;
- result.fixup := namedLabel.GetFixup();
- RETURN TRUE
- END;
- IF ident[0] = "@" THEN
- result.type := Fixup;
- COPY(ident, string);
- Strings.Delete(string,0,1);
- Basic.ToSegmentedName(string, name);
- result.sizeInBits := 32;
- NEW(fixupPatternList, 1);
- fixupPatternList[0].bits := result.sizeInBits;
- fixupPatternList[0].offset := 0;
- identifier.name := name;
- identifier.fingerprint := 0;
- result.fixup := BinaryCode.NewFixup(BinaryCode.Absolute, 0, identifier, 0, 0, 0, fixupPatternList);
- RETURN TRUE
- END;
- symbol := SymbolInScope(ident);
- IF symbol = NIL THEN RETURN FALSE
- ELSIF symbol IS SyntaxTree.Constant THEN RETURN FALSE
- ELSE RETURN NonConstantSymbol(pos,symbol,result)
- END;
- END GetNonConstant;
- PROCEDURE LocalOffset(pos: Position; symbol: SyntaxTree.Symbol; VAR result: Result): BOOLEAN;
- BEGIN
- IF symbol.scope IS SyntaxTree.ProcedureScope THEN (* symbol in procedure (local) scope *)
- IF symbol.scope = scope THEN
- IF (symbol IS SyntaxTree.Variable) OR (symbol IS SyntaxTree.Parameter) THEN
- result.type := ConstantInteger;
- result.value := symbol.offsetInBits DIV module.system.dataUnit;
- ASSERT(symbol.offsetInBits MOD module.system.dataUnit = 0);
- result.sizeInBits := SHORT(module.system.SizeOf(symbol.type));
- RETURN TRUE
- END;
- END;
- END;
- RETURN FALSE
- END LocalOffset;
- PROCEDURE GetConstant*(pos: Position; CONST ident: ARRAY OF CHAR; VAR result: Result): BOOLEAN;
- VAR symbol: SyntaxTree.Symbol; namedResult: NamedResult;
- BEGIN
- namedResult := results.Find(ident);
- IF namedResult # NIL THEN CopyResult(namedResult^,result); RETURN TRUE END;
- symbol := SymbolInScope(ident);
- IF symbol = NIL THEN RETURN FALSE
- ELSIF symbol IS SyntaxTree.Constant THEN RETURN ConstantSymbol(pos,symbol(SyntaxTree.Constant),result)
- ELSIF LocalOffset(pos,symbol,result) THEN RETURN TRUE
- ELSE RETURN FALSE
- END;
- END GetConstant;
- PROCEDURE Factor (VAR x: Result; critical: BOOLEAN): BOOLEAN;
- VAR label: NamedLabel; identifier: Scanner.IdentifierString; pos: Position;
- BEGIN
- IF ThisToken(Scanner.Number) THEN
- (* ASSERT(symbol.numberType = Scanner.Integer); *)
- IF symbol.numberType = Scanner.Integer THEN
- x.value := symbol.integer
- ELSIF symbol.numberType = Scanner.Hugeint THEN
- (* note that 64 bit integer constants are not (yet) supported in expressions by the assembler.
- however, the scanner interprets large 32 bit integers as hugeints (because integers are always assumed to be signed). *)
- x.value := SYSTEM.VAL(LONGINT, symbol.hugeint); (* TODO: how to do that? *)
- ASSERT(x.value < 0); (* the resulting 32 bit integer must be negative when interpreted as a signed value *)
- END;
- x.type := ConstantInteger;
- RETURN TRUE;
- ELSIF ThisToken(Scanner.PC) THEN (* pc IN units ! *)
- x.value := code.pc;
- x.type := ConstantInteger; (* TODO: should it be 'x.type := Offset'? *)
- RETURN TRUE;
- ELSIF ThisToken(Scanner.PCOffset) THEN
- x.value := code.pc-orgOffset;
- x.type := ConstantInteger; (* TODO: should it be 'x.type := Offset'? *)
- RETURN TRUE;
- ELSIF GetIdentifier(pos,identifier) THEN
- label := labels.Find (identifier);
- IF label # NIL THEN
- x.value := label.offset;
- x.type := Offset;
- (*! deal with fixups ? / enter fixup ? *)
- RETURN TRUE;
- ELSIF GetConstant(errorPosition, identifier,x) THEN RETURN TRUE
- ELSIF ~critical & (pass # MaxPasses) THEN
- x.value := 0; x.type := ConstantInteger; RETURN TRUE
- ELSE Error(pos,"undefined symbol"); RETURN FALSE
- END;
- ELSIF ThisToken(Scanner.LeftParenthesis) THEN
- RETURN Expression (x, critical) & ExpectToken(Scanner.RightParenthesis);
- END;
- RETURN FALSE
- END Factor;
- (* term = Factor { ( "*" | "/" | "%" ) Factor } *)
- PROCEDURE Term (VAR x: Result; critical: BOOLEAN): BOOLEAN;
- VAR y: Result; op : LONGINT;
- BEGIN
- IF Factor (x, critical) THEN
- WHILE (symbol.token = Scanner.Times) OR (symbol.token = Scanner.Div) OR (symbol.token = Scanner.Mod) DO
- op := symbol.token; NextSymbol;
- IF Factor (y, critical) THEN
- IF (x.type IN ConstantIntegerOrOffset) & (y.type IN ConstantIntegerOrOffset) THEN
- IF op = Scanner.Times THEN x.value := x.value * y.value
- ELSIF op = Scanner.Div THEN x.value := x.value DIV y.value
- ELSE x.value := x.value MOD y.value
- END;
- ELSIF (x.type = ConstantFloat) OR (y.type = ConstantFloat) THEN
- IF op = Scanner.Times THEN x.valueR := x.valueR * y.valueR
- ELSIF op = Scanner.Div THEN x.valueR := x.valueR / y.valueR
- ELSE RETURN FALSE
- END;
- ELSE RETURN FALSE
- END;
- ELSE
- RETURN FALSE;
- END;
- END;
- RETURN TRUE;
- ELSE
- RETURN FALSE;
- END;
- END Term;
- (* Expression = [ "-" | "+" | "~" ] Term { ( "+" | "-" ) Term } *)
- PROCEDURE Expression*(VAR x: Result; critical: BOOLEAN): BOOLEAN;
- VAR y: Result; op : LONGINT;
- BEGIN
- op := symbol.token;
- IF ThisToken(Scanner.Minus) THEN
- IF Term (x, critical) THEN
- IF x.type IN ConstantIntegerOrOffset THEN
- x.value := -x.value; x.valueR := x.value
- ELSIF x.type = ConstantFloat THEN
- x.valueR := -x.valueR
- ELSE
- RETURN FALSE
- END;
- ELSE
- RETURN FALSE;
- END;
- ELSIF ThisToken(Scanner.Plus) THEN
- IF ~Term (x, critical) THEN RETURN FALSE
- ELSE
- RETURN (x.type IN ConstantIntegerOrOffset) OR (x.type = ConstantFloat)
- END;
- ELSIF ThisToken(Scanner.Not) THEN
- IF Term (x, critical) THEN
- IF x.type IN ConstantIntegerOrOffset THEN
- x.value := -x.value-1; x.valueR := x.value
- ELSE
- RETURN FALSE
- END
- END;
- ELSIF ~Term (x, critical) THEN RETURN FALSE
- END;
- WHILE (symbol.token = Scanner.Plus) OR (symbol.token = Scanner.Minus) DO
- op := symbol.token; NextSymbol;
- IF Term (y, critical) THEN
- IF op = Scanner.Plus THEN
- IF (x.type IN ConstantIntegerOrOffset) & (y.type IN ConstantIntegerOrOffset) THEN
- x.value := x.value+y.value; x.valueR := x.value;
- ELSIF (x.type = ConstantFloat) & (y.type = ConstantFloat) THEN
- x.valueR := x.valueR + y.valueR;
- ELSE RETURN FALSE
- END;
- ELSE
- IF (x.type IN ConstantIntegerOrOffset) & (y.type IN ConstantIntegerOrOffset) THEN
- x.value := x.value-y.value; x.valueR := x.value;
- ELSIF (x.type = ConstantFloat) & (y.type = ConstantFloat) THEN
- x.valueR := x.valueR - y.valueR;
- ELSE RETURN FALSE
- END;
- END;
- ELSE
- RETURN FALSE;
- END;
- END;
- RETURN TRUE;
- END Expression;
- PROCEDURE Data(CONST ident: ARRAY OF CHAR): BOOLEAN;
- VAR size,i,nr: LONGINT; x: Result; pos: Position; result: Result; patterns: ObjectFile.FixupPatterns;
- PROCEDURE Number(ch: CHAR; VAR nr: LONGINT): BOOLEAN;
- BEGIN
- IF (ch >= "0") & (ch <="9") THEN
- nr := ORD(ch)-ORD("0");
- RETURN TRUE
- ELSE
- RETURN FALSE
- END;
- END Number;
- BEGIN
- size := -1;
- IF (ident = "DB") OR (ident = "db") THEN size := 8
- ELSIF (ident="DW") OR (ident = "dw") THEN size := 16
- ELSIF (ident="DD") OR (ident = "dd") THEN size := 32
- ELSIF (ident="DQ") OR (ident = "dq") THEN size := 64
- ELSIF (CAP(ident[0]) ="D") THEN
- size := 0;i := 1;
- WHILE Number(ident[i],nr) DO
- size := size*10+nr; INC(i);
- END;
- IF ident[i] # 0X THEN size := -1 END;
- END;
- IF size = -1 THEN RETURN FALSE
- ELSE
- IF Trace THEN D.String("Data"); D.Ln; END;
- REPEAT
- pos := errorPosition;
- IF symbol.token = Scanner.String THEN
- IF (pass = MaxPasses) & (code.comments # NIL) THEN
- code.comments.String(ident); section.comments.String(' "');
- code.comments.String(symbol.string^);
- code.comments.String('"');
- code.comments.Ln;
- code.comments.Update
- END;
- i := 0;
- WHILE symbol.string[i] # 0X DO
- PutBitsIfLastPass(ORD(symbol.string[i]),size);
- INC(i);
- END;
- NextSymbol;
- ELSIF (symbol.token = Scanner.Identifier) & GetNonConstant(errorPosition,symbol.identifierString,result) THEN
- IF (pass = MaxPasses) & (code.comments # NIL) THEN
- code.comments.String(ident);
- code.comments.String(" ");
- code.comments.String(symbol.identifierString);
- code.comments.Ln;
- code.comments.Update
- END;
- (* if this is the last pass then enter the fixup to the generated code section *)
- IF pass = MaxPasses THEN
- result.fixup.SetFixupOffset(code.pc);
- code.fixupList.AddFixup(result.fixup);
- (* set fixup width *)
- NEW(patterns, 1);
- patterns[0].offset := 0; patterns[0].bits := size;
- result.fixup.InitFixup(result.fixup.mode, result.fixup.offset, result.fixup.symbol, result.fixup.symbolOffset, result.fixup.displacement, 0, patterns);
- END;
- PutBitsIfLastPass(0,size);
- NextSymbol;
- ELSIF Expression(x,FALSE) THEN
- IF x.type # ConstantInteger THEN Error(pos,"forbidden non-constant value") END;
- IF (pass = MaxPasses) & (code.comments # NIL) THEN
- code.comments.String(ident);
- code.comments.String(" ");
- (* code.comments.Int(x.value,1); *)
- (* print number in hexadecimal form *)
- code.comments.String("0");
- code.comments.Hex(x.value, -size DIV 4);
- code.comments.String("H");
- code.comments.Ln;
- code.comments.Update
- END;
- PutBitsIfLastPass(x.value,size);
- ELSE Error(pos,"expected string or expression");
- END;
- UNTIL error OR ~ThisToken(Scanner.Comma);
- END;
- RETURN TRUE
- END Data;
- PROCEDURE Reserve(CONST ident: ARRAY OF CHAR): BOOLEAN;
- BEGIN RETURN FALSE
- END Reserve;
- (** if the assembler is at the last pass: put bits into the binary code section, otherwise only increment the PC **)
- PROCEDURE PutBitsIfLastPass(data: LONGINT; size: BinaryCode.Bits);
- VAR
- oldPC: LONGINT;
- BEGIN
- IF pass = MaxPasses THEN
- code.PutBits(data, size)
- ELSE
- oldPC := code.pc;
- ASSERT(size MOD code.os.unit = 0);
- code.SetPC(oldPC + size DIV code.os.unit)
- END
- END PutBitsIfLastPass;
- PROCEDURE Instruction*(CONST mnemonic: ARRAY OF CHAR);
- VAR numberOperands: LONGINT;
- PROCEDURE ParseOperand(pos: Position; numberOperand: LONGINT);
- (* stub, must be overwritten by implementation *)
- VAR operand: OperandString;
- result: Result; first: BOOLEAN; str: ARRAY 256 OF CHAR;
- BEGIN
- first := TRUE;
- WHILE ~error & (symbol.token # Scanner.Ln) & (symbol.token # Scanner.Comma) DO
- IF (symbol.token = Scanner.Identifier) & GetNonConstant(errorPosition,symbol.identifierString,result) THEN
- D.String("(* non constant ");
- D.String(symbol.identifierString); D.String("="); DumpResult(D.Log,result);
- D.String("*)");
- ELSIF (symbol.token = Scanner.Identifier) & GetConstant(errorPosition,symbol.identifierString,result) THEN
- D.String("(* constant ");
- DumpResult(D.Log,result);
- D.String("*)");
- END;
- IF first THEN first := FALSE ELSE Strings.Append(operand," ") END;
- Scanner.SymbolToString(symbol, scanner.case, str);
- Strings.Append(operand, str);
- NextSymbol;
- END;
- IF Trace THEN
- D.String("operand= ");
- D.String(operand); IF symbol.token = Scanner.Comma THEN D.String(" , ") END;
- END;
- END ParseOperand;
- BEGIN
- IF Trace THEN
- D.String("Instruction= "); D.String(mnemonic); D.String(" ");
- END;
- numberOperands := 0;
- IF ~ThisToken(Scanner.Ln) THEN
- REPEAT
- ParseOperand(errorPosition,numberOperands);
- INC(numberOperands);
- UNTIL error OR ~ThisToken(Scanner.Comma);
- IF ~error & ExpectToken(Scanner.Ln) THEN END;
- END;
- IF Trace THEN D.Ln END
- END Instruction;
- PROCEDURE IgnoreNewLines;
- BEGIN
- WHILE ThisToken(Scanner.Ln) DO END;
- END IgnoreNewLines;
- PROCEDURE DoAssemble();
- VAR result: Result; pos: Position; line,orgCodePos: LONGINT; identifier: Scanner.IdentifierString; context: Scanner.Context;
- BEGIN
- IF Trace THEN
- D.Str("DoAssemble: ");
- IF section # NIL THEN Basic.WriteSegmentedName(D.Log,section.name); D.Ln END;
- END;
- NEW(labels);
- NEW(results);
- scanner.GetContext(context);
- NextSymbol;
- IgnoreNewLines;
- WHILE ~error & (symbol.token # Scanner.Period) & (symbol.token # Scanner.EndOfText) DO
- IF ThisToken(Scanner.Number) THEN
- line := symbol.integer;
- IF ThisToken(Scanner.Colon) THEN (* line number *)
- ELSE Error(symbol.position,"Identifier expected");
- END;
- END;
- IF ExpectIdentifier(pos,identifier) THEN
- IF ThisToken(Scanner.Colon) THEN (* label *)
- DefineLabel(pos,identifier)
- ELSIF ThisIdentifier("equ") OR ThisToken(Scanner.Equal) THEN
- IF Expression(result,FALSE) THEN DefineResult(pos,identifier,result) END;
- ELSE scanner.SkipToEndOfLine; NextSymbol;
- END;
- END;
- IgnoreNewLines;
- END;
- orgCodePos := code.pc;
- FOR pass := 1 TO MaxPasses DO
- labels.ResetDisplacements; (* this is important as the displacement is corrected by code emission in a cummulative way *)
- code.SetPC(orgCodePos);
- SetContext(context);
- IgnoreNewLines;
- WHILE ~error & (symbol.token # Scanner.EndOfText) & (symbol.token # Scanner.Period) DO
- IF ThisToken(Scanner.Number) THEN
- line := symbol.integer;
- IF ThisToken(Scanner.Colon) THEN (* line number *)
- ELSE Error(symbol.position,"Identifier expected");
- END;
- END;
- IF ExpectIdentifier(pos,identifier) THEN
- IF ThisToken(Scanner.Colon) THEN (* label *)
- SetLabel(pos,identifier);
- ELSIF ThisIdentifier("equ") OR ThisToken(Scanner.Equal) THEN (* constant definition *)
- IF Expression(result,FALSE) THEN SetResult(identifier,result) END;
- ELSE
- IF identifier = "section" THEN
- Section()
- ELSIF Data(identifier) THEN
- ELSIF Reserve(identifier) THEN
- ELSIF identifier = "fixed" THEN
- IF ExpectConstantInteger(result,TRUE) THEN
- code.SetAlignment(TRUE,result.value)
- END;
- ELSIF ~error THEN
- errorPosition := pos;
- Instruction(identifier);
- (*
- IF ~error & ExpectToken(Scanner.Ln) THEN END;
- *)
- END;
- END;
- END;
- IgnoreNewLines;
- END;
- END;
- IF Trace THEN
- D.Str("END Assemble"); D.Ln;
- END
- END DoAssemble;
- PROCEDURE InlineAssemble*(scanner: Scanner.AssemblerScanner; section: IntermediateCode.Section; scope: SyntaxTree.Scope; module: Sections.Module);
- BEGIN
- ASSERT(module # NIL); ASSERT(scanner # NIL); ASSERT(section # NIL);
- ASSERT(section.resolved # NIL);
- SELF.scope := scope;
- SELF.module := module;
- SELF.scanner := scanner;
- SELF.section := section;
- SELF.code := section.resolved;
- DoAssemble;
- END InlineAssemble;
- PROCEDURE Assemble*(scanner: Scanner.AssemblerScanner);
- BEGIN
- ASSERT(scanner # NIL);
- SELF.scanner := scanner;
- module := NIL; section := NIL; scope := NIL;
- scanner.SetContext(scanner.startContext);
- DoAssemble;
- END Assemble;
- PROCEDURE AllSections*;
- VAR pos: Position; sectionType, sectionName: Scanner.IdentifierString;
- BEGIN
- IF Trace THEN D.String("AllSections"); D.Ln END;
- SetContext(scanner.startContext);
- IgnoreNewLines;
- WHILE ThisToken(Scanner.Period) & ExpectIdentifier(pos,sectionType) & ExpectIdentifier(pos,sectionName) DO
- D.String("section "); D.String(sectionType); D.String(" "); D.String(sectionName); D.Ln;
- DoAssemble;
- END;
- END AllSections;
- PROCEDURE Text*(scanner: Scanner.AssemblerScanner);
- BEGIN
- ASSERT(scanner # NIL);
- SELF.scanner := scanner;
- module := NIL; section := NIL; scope := NIL;
- AllSections;
- END Text;
- END Assembler;
- PROCEDURE DumpResult*(w: Streams.Writer; result: Result);
- BEGIN
- CASE result.type OF
- ConstantInteger: w.String("i"); w.Int(result.sizeInBits,1);w.String(" ");w.Int(result.value,1);
- |ConstantFloat: w.String("f");w.Int(result.sizeInBits,1);w.String(" ");w.Float(result.value,20);
- |Offset: w.String("ofs "); w.Int(result.value,1);
- |Fixup: w.String("i"); w.Int(result.sizeInBits,1);w.String(" "); w.String("fixup ");
- result.fixup.Dump(w);
- END;
- END DumpResult;
- PROCEDURE Test*(context: Commands.Context);
- VAR scanner: Scanner.AssemblerScanner; diagnostics: Diagnostics.StreamDiagnostics; assembler: Assembler;
- BEGIN
- NEW(diagnostics,context.out);
- NEW(scanner,"command",context.arg,0,diagnostics);
- NEW(assembler,diagnostics);
- assembler.Text(scanner);
- (*
- assembler.Assemble(scanner);
- *)
- END Test;
- PROCEDURE TestScanner*(context: Commands.Context);
- VAR scanner: Scanner.AssemblerScanner; diagnostics: Diagnostics.StreamDiagnostics; symbol: Scanner.Symbol;
- BEGIN
- NEW(diagnostics,context.out);
- NEW(scanner,"command",context.arg,0,diagnostics);
- WHILE scanner.GetNextSymbol(symbol) & (symbol.token # Scanner.EndOfText) DO
- Scanner.OutSymbol(context.out, symbol); context.out.Ln;
- END;
- END TestScanner;
- END FoxAssembler.
- SystemTools.Free FoxAssembler ~
- FoxAssembler.Test
- ;---------------- intermediate code -----------------
- .module BitSets
- .imports SYSTEM
- .const BitSets.@moduleSelf offset=0
- 0: data u32 0
- .const BitSets.BitSet offset=0
- 0: data u32 0
- .code BitSets.BitSet.InitBitSet offset=0
- 0: enter 0, 0
- 1: mov u32 r1, u32 [fp+8]
- 2: mov s32 [r1], s32 [fp+12]
- 3: push s32 [fp+12]
- 4: mov u32 r2, u32 [fp+8]
- 5: add u32 r3, u32 [r2-4], u32 -88
- 6: push u32 r2
- 7: call u32 [r3], 8
- 8: leave 0
- 9: exit 8
- .code BitSets.BitSet.Zero offset=0
- 0: enter 0, 8
- 1: mov s32 [fp-4], s32 0
- 2: mov u32 r1, u32 [fp+8]
- 3: mov u32 r2, u32 [r1+4]
- 4: conv s32 r3, u32 [r2+12]
- 5: sub s32 r3, s32 r3, s32 1
- 6: mov s32 [fp-8], s32 r3
- 7: brlt u32 BitSets.BitSet.Zero:21, s32 [fp-8], s32 [fp-4]
- 8: br u32 BitSets.BitSet.Zero:9
- 9: conv u32 r4, s32 [fp-4]
- 10: mov u32 r5, u32 r4
- 11: mov u32 r6, u32 [fp+8]
- 12: mov u32 r7, u32 [r6+4]
- 13: brlt u32 BitSets.BitSet.Zero:15, u32 r4, u32 [r7+12]
- 14: trap 7
- 15: mul u32 r5, u32 r5, u32 4
- 16: add u32 r5, u32 r5, u32 r7+16
- 17: mov u32 [r5], u32 0
- 18: add s32 r8, s32 [fp-4], s32 1
- 19: mov s32 [fp-4], s32 r8
- 20: br u32 BitSets.BitSet.Zero:7
- 21: leave 0
- 22: exit 4
- .code BitSets.BitSet.Resize offset=0
- 0: enter 0, 12
- 1: brlt u32 BitSets.BitSet.Resize:3, s32 [fp+12], s32 0
- 2: br u32 BitSets.BitSet.Resize:4
- 3: trap 8
- 4: mov u32 r1, u32 [fp+8]
- 5: mov s32 [r1], s32 [fp+12]
- 6: sub s32 r2, s32 [fp+12], s32 1
- 7: brlt u32 BitSets.BitSet.Resize:10, s32 r2, s32 0
- 8: mov s32 r2, s32 r2
- 9: br u32 BitSets.BitSet.Resize:11
- 10: mov s32 r2, s32 0, s32 r2
- 11: shr s32 r2, s32 r2, s32 5
- 12: add s32 r2, s32 r2, s32 1
- 13: mov s32 [fp+12], s32 r2
- 14: mov u32 r3, u32 [fp+8]
- 15: breq u32 BitSets.BitSet.Resize:35, u32 [r3+4], u32 0
- 16: br u32 BitSets.BitSet.Resize:17
- 17: mov u32 r4, u32 [fp+8]
- 18: mov u32 r5, u32 [r4+4]
- 19: conv s32 r6, u32 [r5+12]
- 20: brlt u32 BitSets.BitSet.Resize:25, s32 r6, s32 [fp+12]
- 21: br u32 BitSets.BitSet.Resize:22
- 22: leave 0
- 23: exit 8
- 24: br u32 BitSets.BitSet.Resize:25
- 25: mov u32 r7, u32 [fp+8]
- 26: mov u32 r8, u32 [r7+4]
- 27: conv s32 r9, u32 [r8+12]
- 28: shl s32 r9, s32 r9, s32 1
- 29: brlt u32 BitSets.BitSet.Resize:32, s32 [fp+12], s32 r9
- 30: mov s32 r9, s32 [fp+12]
- 31: br u32 BitSets.BitSet.Resize:33
- 32: mov s32 r9, s32 r9, s32 r9
- 33: mov s32 [fp+12], s32 r9
- 34: br u32 BitSets.BitSet.Resize:35
- 35: brge u32 BitSets.BitSet.Resize:37, s32 [fp+12], s32 0
- 36: trap 9
- 37: push s32 [fp+12]
- 38: mov s32 r10, s32 [fp+12]
- 39: conv u32 r10, s32 r10
- 40: mul u32 r10, u32 r10, u32 4
- 41: add u32 r10, u32 r10, u32 16
- 42: push u32 fp-4
- 43: push u32 fp-4
- 44: push u32 r10
- 45: push u8 0
- 46: call u32 $SystemCall2:0, 0
- 47: pop u32 r11
- 48: mov u32 r12, u32 [r11]
- 49: breq u32 BitSets.BitSet.Resize:53, u32 r12, u32 0
- 50: pop u32 r13
- 51: mov u32 [r12+12], u32 r13
- 52: br u32 BitSets.BitSet.Resize:54
- 53: add u32 sp, u32 sp, u32 4
- 54: mov u32 r14, u32 [fp+8]
- 55: breq u32 BitSets.BitSet.Resize:85, u32 [r14+4], u32 0
- 56: br u32 BitSets.BitSet.Resize:57
- 57: mov s32 [fp-8], s32 0
- 58: mov u32 r15, u32 [fp+8]
- 59: mov u32 r16, u32 [r15+4]
- 60: conv s32 r17, u32 [r16+12]
- 61: sub s32 r17, s32 r17, s32 1
- 62: mov s32 [fp-12], s32 r17
- 63: brlt u32 BitSets.BitSet.Resize:84, s32 [fp-12], s32 [fp-8]
- 64: br u32 BitSets.BitSet.Resize:65
- 65: conv u32 r18, s32 [fp-8]
- 66: mov u32 r19, u32 r18
- 67: mov u32 r20, u32 [fp+8]
- 68: mov u32 r21, u32 [r20+4]
- 69: brlt u32 BitSets.BitSet.Resize:71, u32 r18, u32 [r21+12]
- 70: trap 7
- 71: mul u32 r19, u32 r19, u32 4
- 72: add u32 r19, u32 r19, u32 r21+16
- 73: conv u32 r22, s32 [fp-8]
- 74: mov u32 r23, u32 r22
- 75: mov u32 r24, u32 [fp-4]
- 76: brlt u32 BitSets.BitSet.Resize:78, u32 r22, u32 [r24+12]
- 77: trap 7
- 78: mul u32 r23, u32 r23, u32 4
- 79: add u32 r23, u32 r23, u32 r24+16
- 80: mov u32 [r23], u32 [r19]
- 81: add s32 r25, s32 [fp-8], s32 1
- 82: mov s32 [fp-8], s32 r25
- 83: br u32 BitSets.BitSet.Resize:63
- 84: br u32 BitSets.BitSet.Resize:85
- 85: mov u32 r26, u32 [fp+8]
- 86: mov u32 [r26+4], u32 [fp-4]
- 87: leave 0
- 88: exit 8
- .code BitSets.BitSet.GetSize offset=0
- 0: enter 0, 0
- 1: mov u32 r1, u32 [fp+8]
- 2: return s32 [r1]
- 3: leave 0
- 4: exit 4
- 5: trap 3
|