1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072 |
- 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*: HUGEINT;
- 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;
- token-: Scanner.Token;
- 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); NextToken;
- END SetContext;
- PROCEDURE Error*(pos: SyntaxTree.Position; CONST msg: ARRAY OF CHAR);
- BEGIN
- error := TRUE;
- Basic.Error(diagnostics, scanner.source^,pos, msg);
- 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 NextToken*;
- BEGIN error := error OR ~scanner.GetNextToken(token); errorPosition := token.position;
- END NextToken;
- PROCEDURE ThisSymbol*(x: Scanner.Symbol): BOOLEAN;
- BEGIN
- IF ~error & (token.symbol = x) THEN NextToken; RETURN TRUE ELSE RETURN FALSE END;
- END ThisSymbol;
- PROCEDURE GetIdentifier*(VAR pos: Position; VAR identifier: ARRAY OF CHAR): BOOLEAN;
- BEGIN
- pos := token.position;
- IF token.symbol # Scanner.Identifier THEN RETURN FALSE
- ELSE COPY(token.identifierString,identifier); NextToken; RETURN TRUE
- END;
- END GetIdentifier;
- PROCEDURE ThisIdentifier*(CONST this: ARRAY OF CHAR): BOOLEAN;
- BEGIN
- IF ~error & (token.symbol = Scanner.Identifier) & (this = token.identifierString) THEN NextToken; 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 ExpectSymbol*(x: Scanner.Symbol): BOOLEAN;
- VAR s: Basic.MessageString;
- BEGIN
- IF ThisSymbol(x) THEN RETURN TRUE
- ELSE
- s := "expected token "; Strings.Append(s,Scanner.symbols[x]); Strings.Append(s," but got "); Strings.Append(s,Scanner.symbols[token.symbol]);
- Error(errorPosition,s);RETURN FALSE
- END;
- END ExpectSymbol;
- 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 ExpectSymbol(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
- NextToken;
- IF ExpectSymbol(Scanner.Period) & (token.symbol = Scanner.Identifier) THEN
- identifier := SyntaxTree.NewIdentifier(token.identifierString);
- IF Trace THEN D.String("GetScopeSymbol :"); D.String(token.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): Basic.Fingerprint;
- 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 ThisSymbol(Scanner.Number) THEN
- (* ASSERT(symbol.numberType = Scanner.Integer); *)
- IF token.numberType = Scanner.Integer THEN
- x.value := token.integer
- ELSIF token.numberType = Scanner.Hugeint THEN
- x.value := token.hugeint;
- (* 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 ThisSymbol(Scanner.PC) THEN (* pc IN units ! *)
- x.value := code.pc;
- x.type := ConstantInteger; (* TODO: should it be 'x.type := Offset'? *)
- RETURN TRUE;
- ELSIF ThisSymbol(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 ThisSymbol(Scanner.LeftParenthesis) THEN
- RETURN Expression (x, critical) & ExpectSymbol(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 (token.symbol = Scanner.Times) OR (token.symbol = Scanner.Div) OR (token.symbol = Scanner.Mod) DO
- op := token.symbol; NextToken;
- 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 := token.symbol;
- IF ThisSymbol(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 ThisSymbol(Scanner.Plus) THEN
- IF ~Term (x, critical) THEN RETURN FALSE
- ELSE
- RETURN (x.type IN ConstantIntegerOrOffset) OR (x.type = ConstantFloat)
- END;
- ELSIF ThisSymbol(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 (token.symbol = Scanner.Plus) OR (token.symbol = Scanner.Minus) DO
- op := token.symbol; NextToken;
- 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 token.symbol = Scanner.String THEN
- IF (pass = MaxPasses) & (code.comments # NIL) THEN
- code.comments.String(ident); section.comments.String(' "');
- code.comments.String(token.string^);
- code.comments.String('"');
- code.comments.Ln;
- code.comments.Update
- END;
- i := 0;
- WHILE token.string[i] # 0X DO
- PutBitsIfLastPass(ORD(token.string[i]),size);
- INC(i);
- END;
- NextToken;
- ELSIF (token.symbol = Scanner.Identifier) & GetNonConstant(errorPosition,token.identifierString,result) THEN
- IF (pass = MaxPasses) & (code.comments # NIL) THEN
- code.comments.String(ident);
- code.comments.String(" ");
- code.comments.String(token.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);
- NextToken;
- 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 ~ThisSymbol(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: HUGEINT; 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 & (token.symbol # Scanner.Ln) & (token.symbol # Scanner.Comma) DO
- IF (token.symbol = Scanner.Identifier) & GetNonConstant(errorPosition,token.identifierString,result) THEN
- D.String("(* non constant ");
- D.String(token.identifierString); D.String("="); DumpResult(D.Log,result);
- D.String("*)");
- ELSIF (token.symbol = Scanner.Identifier) & GetConstant(errorPosition,token.identifierString,result) THEN
- D.String("(* constant ");
- DumpResult(D.Log,result);
- D.String("*)");
- END;
- IF first THEN first := FALSE ELSE Strings.Append(operand," ") END;
- Scanner.TokenToString(token, scanner.case, str);
- Strings.Append(operand, str);
- NextToken;
- END;
- IF Trace THEN
- D.String("operand= ");
- D.String(operand); IF token.symbol = 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 ~ThisSymbol(Scanner.Ln) THEN
- REPEAT
- ParseOperand(errorPosition,numberOperands);
- INC(numberOperands);
- UNTIL error OR ~ThisSymbol(Scanner.Comma);
- IF ~error & ExpectSymbol(Scanner.Ln) THEN END;
- END;
- IF Trace THEN D.Ln END
- END Instruction;
- PROCEDURE IgnoreNewLines;
- BEGIN
- WHILE ThisSymbol(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);
- NextToken;
- IgnoreNewLines;
- WHILE ~error & (token.symbol # Scanner.Period) & (token.symbol # Scanner.EndOfText) DO
- IF ThisSymbol(Scanner.Number) THEN
- line := token.integer;
- IF ThisSymbol(Scanner.Colon) THEN (* line number *)
- ELSE Error(token.position,"Identifier expected");
- END;
- END;
- IF ExpectIdentifier(pos,identifier) THEN
- IF ThisSymbol(Scanner.Colon) THEN (* label *)
- DefineLabel(pos,identifier)
- ELSIF ThisIdentifier("equ") OR ThisSymbol(Scanner.Equal) THEN
- IF Expression(result,FALSE) THEN DefineResult(pos,identifier,result) END;
- ELSE scanner.SkipToEndOfLine; NextToken;
- 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 & (token.symbol # Scanner.EndOfText) & (token.symbol # Scanner.Period) DO
- IF ThisSymbol(Scanner.Number) THEN
- line := token.integer;
- IF ThisSymbol(Scanner.Colon) THEN (* line number *)
- ELSE Error(token.position,"Identifier expected");
- END;
- END;
- IF ExpectIdentifier(pos,identifier) THEN
- IF ThisSymbol(Scanner.Colon) THEN (* label *)
- SetLabel(pos,identifier);
- ELSIF ThisIdentifier("equ") OR ThisSymbol(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,LONGINT(result.value))
- END;
- ELSIF ~error THEN
- errorPosition := pos;
- Instruction(identifier);
- (*
- IF ~error & ExpectSymbol(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 ThisSymbol(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);
- scanner := Scanner.NewAssemblerScanner("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; token: Scanner.Token;
- BEGIN
- NEW(diagnostics,context.out);
- scanner := Scanner.NewAssemblerScanner("command",context.arg,0,diagnostics);
- WHILE scanner.GetNextToken(token) & (token.symbol # Scanner.EndOfText) DO
- Scanner.PrintToken(context.out, token); context.out.Ln;
- END;
- END TestScanner;
- END FoxAssembler.
- System.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
|