Extracting Assembler Tokens
This procedure scans assembler instruction and returns the next assembler token.
Procedure GetNextAsmToken;
Procedure SeparateAsmWord;
Var C: Char;
Function IsLetterOrNumberOrSpecialCharacter: Boolean;
begin
Case C of
'0'..'9',
'A'..'Z',
'a'..'z',
'_',
'$',
'@',
'&',
'?' : IsLetterOrNumberOrSpecialCharacter := True;
else IsLetterOrNumberOrSpecialCharacter := False;
end;
end;
Function IsString: Boolean;
Var StringChar, StringDelimiter: Char;
begin
IsString := False;
If not (C in ['''', '"']) then Exit;
StringDelimiter := C;
AsmString := '';
IsString := True;
Repeat
StringChar := GetNextChar;
If StringChar = #0 then AsmError (StringConstantExceedsLine);
If StringChar = StringDelimiter then
begin
StringChar := GetNextChar;
If StringChar <> StringDelimiter then Exit;
end;
If Byte (AsmString [0]) = 127 then AsmError (StringConstantExceedsLine);
Inc (AsmString [0]);
AsmString [Length (AsmString)] := StringChar;
until False;
end;
begin
AsmTokenString := '';
AsmTokenUpCaseString := '';
AsmWordHash := 0;
C := GetFirstNonBlankCharacter;
AsmSourceErrorPosition := AsmCharacterPointer;
If C <> #0 then
begin
If IsLetterOrNumberOrSpecialCharacter then
begin
Repeat
If Length (AsmTokenString) < 32 then
begin
Inc (AsmTokenString [0]);
Inc (AsmTokenUpCaseString [0]);
AsmTokenString [Byte (AsmTokenString [0])] := C;
AsmTokenUpCaseString [Byte (AsmTokenUpCaseString [0])] := UpCase (C);
Inc (AsmWordHash, Ord (UpCase (C)) - 1);
end;
C := GetNextChar;
until (C = #0) or not IsLetterOrNumberOrSpecialCharacter;
AsmWordType := 1;
If AsmTokenUpCaseString <> 'END' then Exit;
end else begin
AsmWordType := 2;
If IsString then Exit;
AsmWordType := 0;
AsmTokenString := C;
Case C of
';', '{':
{$B+}
else If (C <> '(') or (GetNextChar <> '*') then Exit;
{$B-}
end;
end;
end;
AsmWordType := 0;
AsmTokenString := ';';
LineCharacterCounter := 0;
AsmCharacterPointer := AsmSourceErrorPosition;
end;
Function FindAsmWord (AsmList: PIdentifierList; Var AsmWordData: Pointer): Boolean;
Var AsmWord: PAsmWord absolute AsmWordData;
AsmWordOffset: Word absolute AsmWordData;
begin
FindAsmWord := False;
If AsmWordType <> 1 then Exit;
AsmWord := Ptr (DSeg, AsmList^.Offset [AsmWordHash and AsmList^.Mask]);
While AsmWordOffset <> 0 do
begin
AsmToken := AsmToken_00;
If AsmWord^.Str = AsmTokenUpCaseString then
begin
Inc (AsmWordOffset, Length (AsmWord^.Str) + 3);
FindAsmWord := True;
Exit;
end;
AsmWordOffset := AsmWord^.NextWordOffset;
end;
end;
Function IsAsmInstruction: Boolean;
begin
If FindAsmWord (@AsmInstructions, Pointer (InstructionData)) then
begin
AsmToken := AsmToken_Instruction;
IsAsmInstruction := True;
end else IsAsmInstruction := False;
end;
Function IsSymbolToken: Boolean;
begin
IsSymbolToken := False;
If AsmWordType = 0 then
begin
AsmToken := TAsmToken (AsmTokenString [1]);
If (Length (AsmTokenString) = 1) and (AsmTokenString [1] <> #0) then IsSymbolToken := True;
end;
end;
Function IsAsmOperand: Boolean;
Var OperandData: POperandData;
begin
If FindAsmWord (@AsmOperands, Pointer (OperandData)) then
begin
AsmToken := OperandData^.Token;
OperandRegisterType := OperandData^.RegisterType;
OperandRegister := OperandData^.Register;
NumericAsmConstant.Long := OperandData^.W1;
IsAsmOperand := True;
end else IsAsmOperand := False;
end;
Function IsAsmConstant: Boolean;
Var StartIndex, EndIndex: Byte;
Index: Integer;
Constant: LongRec;
Procedure ProcessHexNumber;
Var Index: Integer;
begin
For Index := StartIndex to EndIndex do
begin
If NumericAsmConstant.WordH > $0FFF then AsmError (ConstantOutOfRange);
NumericAsmConstant.Long := NumericAsmConstant.Long * 16;
If (NumericAsmConstant.WordH = $FFFF) and (NumericAsmConstant.WordL > $FFF0) then AsmError (ConstantOutOfRange);
If AsmTokenUpCaseString [Index] in ['0'..'9'] then
Inc (NumericAsmConstant.Long, Ord (AsmTokenUpCaseString [Index]) - Ord ('0')) else
If AsmTokenUpCaseString [Index] in ['A'..'F'] then
Inc (NumericAsmConstant.Long, Ord (AsmTokenUpCaseString [Index]) - Ord ('A') + 10) else
AsmError (ErrorInIntegerConstant);
end;
end;
Procedure ProcessDecNumber;
Var Index: Integer;
begin
For Index := StartIndex to EndIndex do
begin
If NumericAsmConstant.WordH > $1999 then AsmError (ConstantOutOfRange);
If (NumericAsmConstant.WordH = $1999) and (NumericAsmConstant.WordL > $9999) then AsmError (ConstantOutOfRange);
NumericAsmConstant.Long := NumericAsmConstant.Long * 10;
If (NumericAsmConstant.WordH = $FFFF) and (NumericAsmConstant.WordL > $FFFF - 9) then AsmError (ConstantOutOfRange);
If AsmTokenUpCaseString [Index] in ['0'..'9'] then
Inc (NumericAsmConstant.Long, Ord (AsmTokenUpCaseString [Index]) - Ord ('0')) else
AsmError (ErrorInIntegerConstant);
end;
end;
Procedure ProcessOctNumber;
Var Index: Integer;
begin
For Index := StartIndex to EndIndex do
begin
If NumericAsmConstant.WordH > $1FFF then AsmError (ConstantOutOfRange);
NumericAsmConstant.Long := NumericAsmConstant.Long * 8;
If (NumericAsmConstant.WordH = $FFFF) and (NumericAsmConstant.WordL > $FFFF - 7) then AsmError (ConstantOutOfRange);
If AsmTokenUpCaseString [Index] in ['0'..'7'] then
Inc (NumericAsmConstant.Long, Ord (AsmTokenUpCaseString [Index]) - Ord ('0')) else
AsmError (ErrorInIntegerConstant);
end;
end;
Procedure ProcessBinNumber;
Var Index: Integer;
begin
For Index := StartIndex to EndIndex do
begin
If NumericAsmConstant.WordH > $7FFF then AsmError (ConstantOutOfRange);
NumericAsmConstant.Long := NumericAsmConstant.Long * 2;
If (NumericAsmConstant.WordH = $FFFF) and (NumericAsmConstant.WordL > $FFFF - 1) then AsmError (ConstantOutOfRange);
If AsmTokenUpCaseString [Index] in ['0'..'1'] then
Inc (NumericAsmConstant.Long, Ord (AsmTokenUpCaseString [Index]) - Ord ('0')) else
AsmError (ErrorInIntegerConstant);
end;
end;
begin
IsAsmConstant := False;
NumericAsmConstant.Long := 0;
Case AsmWordType of
1: begin
AsmString := '';
StartIndex := 2;
EndIndex := Length (AsmTokenUpCaseString);
If AsmTokenUpCaseString [1] = '$' then ProcessHexNumber else
If AsmTokenUpCaseString [1] in ['0'..'9'] then
begin
StartIndex := 1;
If AsmTokenUpCaseString [Length (AsmTokenUpCaseString)] in ['0'..'9'] then ProcessDecNumber else
begin
Dec (EndIndex);
Case AsmTokenUpCaseString [Length (AsmTokenUpCaseString)] of
'D': ProcessDecNumber;
'B': ProcessBinNumber;
'O': ProcessOctNumber;
'H': ProcessHexNumber;
else AsmError (ErrorInIntegerConstant);
end;
end;
end else Exit;
AsmToken := AsmToken_Constant;
IsAsmConstant := True;
end;
2: begin
For Index := 1 to Length (AsmString) do
begin
NumericAsmConstant.WordH := NumericAsmConstant.WordH and $00FF;
NumericAsmConstant.Long := NumericAsmConstant.Long shl 8 + Byte (AsmString [Index]);
end;
AsmToken := AsmToken_Constant;
IsAsmConstant := True;
end;
end;
end;
Procedure ProcessAsmIdentifier;
Var IdToken: TToken;
IdentifierDataPointer: Pointer;
TypeDefinition: PTypeDefinition;
VariableIdentifierData: PVariableIdentifierData;
Procedure SetAsmVariableIdentifierData;
begin
With AsmIdentifierData do
If vfVar in VariableIdentifierData^.Flags then
begin
AdditionalPointer := nil;
Size := 4;
end else begin
TypeDefinition := PointerFromOffsets (PVariableIdentifierData (
IdentifierDataPointer)^.UnitTypeOffsets);
Case TypeDefinition^.BaseType of
btRecord,
btObject: AdditionalPointer := TypeDefinition;
else AdditionalPointer := nil;
end;
Size := TypeDefinition^.Size;
end;
end;
begin
If AsmTokenString [1] = '&' then
begin
If Length (AsmTokenString) = 1 then AsmError (SyntaxError);
Delete (AsmTokenString, 1, 1);
end;
CopyStringToCurrentIdentifier (AsmTokenString);
AsmIdentifierData.AdditionalPointer := AsmIdentifierAdditionalData;
If not IsValidAsmIdentifier (Pointer (Pointer (@AsmIdentifierData)^), IdToken,
IdentifierDataPointer, CurrentIdentifierOffset) then
AsmError (UnknownIdentifier);
With AsmIdentifierData do
begin
ReferencedData.Long := $FFFFFFFF;
Value_Lo := 0;
Value_Hi := 0;
Case IdToken of
Token_ConstantIdentifier:
Case PTypeDefinition (PointerFromOffsets (PConstantIdentifierData (IdentifierDataPointer)^.
UnitTypeOffsets))^.BaseType of
btPointer,
btInteger..btEnumeration: begin
AdditionalPointer := nil;
Value_Lo := PConstantIdentifierData (IdentifierDataPointer)^.OrdinalValue;
Value_Hi := PConstantIdentifierData (IdentifierDataPointer)^.W2;
Size := 0;
end;
else AsmError (InvalidSymbolReference);
end;
Token_TypeIdentifier:
begin
TypeDefinition := PointerFromOffsets (PTypeIdentifierData (IdentifierDataPointer)^.UnitTypeOffsets);
begin
Case TypeDefinition^.BaseType of
btRecord,
btObject: AdditionalPointer := TypeDefinition;
else AdditionalPointer := nil;
end;
Size := TypeDefinition^.Size;
end;
end;
Token_VariableIdentifier:
begin
VariableIdentifierData := IdentifierDataPointer;
While vfAbsoluteVar in VariableIdentifierData^.Flags do
VariableIdentifierData :=
PVariableIdentifierData (PointerFromOffsets (VariableIdentifierData^.AbsoluteVarDataOffsets));
If Field in VariableIdentifierData^.Flags then
begin
Value_Lo := VariableIdentifierData^.W1.Ofs;
Value_Hi := 0;
SetAsmVariableIdentifierData;
end else If VariableIdentifierData^.Flags * VariableTypeMask = VariableAbsoluteAddress then
begin
Dec (ReferencedData.WordL);
Value_Lo := VariableIdentifierData^.W1.Ofs;
Value_Hi := VariableIdentifierData^.W1.Seg;
SetAsmVariableIdentifierData;
end else If VariableIdentifierData^.Flags * VariableTypeMask = LocalStackVariable then
begin
Dec (ReferencedData.WordL, 2);
Value_Lo := VariableIdentifierData^.W1.Ofs;
Value_Hi := 0;
SetAsmVariableIdentifierData;
end else begin
ReferencedData.WordL := VariableIdentifierData^.W1.Seg;
If VariableIdentifierData^.Flags = [] then
ReferencedData.WordH := $8000 else
ReferencedData.WordH := $C000;
ReferencedData.WordH :=
ReferencedData.WordH or AddReferencedModule (Seg (VariableIdentifierData^));
Value_Lo := VariableIdentifierData^.W1.Ofs;
Value_Hi := 0;
SetAsmVariableIdentifierData;
end;
end;
Token_ProcedureIdentifier:
begin
If pfInline in PProcedureIdentifierData (IdentifierDataPointer)^.Flags then AsmError (InvalidSymbolReference);
ReferencedData.WordL := PProcedureIdentifierData (IdentifierDataPointer)^.ProceduresRecordOffset;
ReferencedData.WordH := AddReferencedModule (Seg (IdentifierDataPointer^));
If pfFar in PProcedureIdentifierData (IdentifierDataPointer)^.Flags then Size := $FFFE else Size := $FFFF;
AdditionalPointer := nil;
end;
Token_UnitIdentifier:
begin
AdditionalPointer := Ptr (PUnitIdentifierData (IdentifierDataPointer)^.UnitSegment, 0);
Size := 0;
end;
Token_LabelIdentifier:
begin
If CurrentIdentifierOffset < Ofs (CurrentScopeIdentifierTableAddress^) then
AsmError (LabelNotWithinCurrentBlock);
ReferencedData.WordL := CurrentIdentifierOffset;
ReferencedData.WordH := $4000 or AddReferencedModule (Seg (IdentifierDataPointer^));
AdditionalPointer := nil;
Size := $FFFD;
end;
Token_AsmSegmentReference:
begin
ReferencedData.WordL := 0;
ReferencedData.WordH := Swap (Byte (IdentifierDataPointer^)) or
AddReferencedModule (SymbolTable [stMain].Segment);
AdditionalPointer := nil;
Size := $FFF0;
end;
Token_AsmOffsetReference:
begin
If ProcedureIdentifierDataOffset = 0 then AsmError (InvalidSymbolReference);
Case Byte (IdentifierDataPointer^) of { In TPC only one byte, in TPC16 word }
0: begin { @LOCALS }
AdditionalPointer := nil;
Value_Lo := - (ProgramBlockMaxStackFrameOffset and $FFFE);
Value_Hi := 0;
Size := 0;
end;
1: begin { @PARAMS }
AdditionalPointer := nil;
Value_Lo := PushedParametersSize;
Value_Hi := 0;
Size := 0;
end;
2: begin { @RESULT }
TypeDefinition := PointerFromOffsets (PProcedureIdentifierData (Ptr (SymbolTable [stMain].Segment,
ProcedureIdentifierDataOffset))^.ProcedureTypeDefinition.ResultTypeOffset);
If Ofs (TypeDefinition^) = 0 then AsmError (InvalidSymbolReference);
Value_Lo := OffsetAfterLastParameter;
Value_Hi := 0;
Size := 4;
If TypeDefinition^.BaseType <> btString then
begin
If pfAssembler in PProcedureIdentifierData (Ptr (SymbolTable [stMain].Segment,
ProcedureIdentifierDataOffset))^.Flags then AsmError (InvalidSymbolReference);
Value_Lo := FunctionResultNegativeSize;
Size := TypeDefinition^.Size;
end;
ReferencedData.Long := $FFFFFFFD;
AdditionalPointer := nil;
end;
end;
end;
else AsmError (InvalidSymbolReference);
end;
If Size >= $FFFD then CodeIdentifierReference := True else CodeIdentifierReference := False;
end;
AsmIdentifierAdditionalData := AsmIdentifierData.AdditionalPointer;
AsmToken := AsmToken_Identifier;
end;
begin
AsmToken := AsmToken_Semicolon;
If LineCharacterCounter <> 0 then
begin
SeparateAsmWord;
If not BeforeOperands or not IsAsmInstruction then
begin
If not IsSymbolToken then
If not IsAsmOperand then
If not IsAsmConstant then
If not BeforeOperands then ProcessAsmIdentifier;
end;
end;
If AsmToken = AsmToken_00 then AsmToken := AsmToken_01;
end;
If AsmToken
is expected assembler token this procedure gets next one, otherwise it reports error.
Procedure ExpectAsmTokenAndGetNext (ExpectedAsmToken: TAsmToken);
begin
If AsmToken <> ExpectedAsmToken then AsmError (SyntaxError);
GetNextAsmToken;
end;
If assembler tokenĀ is AsmTokenToCheck
, this function gets the next token and returns True
otherwise it returns False
.
Function CheckAndGetNextAsmToken (AsmTokenToCheck: TAsmToken): Boolean;
begin
CheckAndGetNextAsmToken := True;
If AsmToken = AsmTokenToCheck then GetNextAsmToken else CheckAndGetNextAsmToken := False;
end;
This function finds AsmToken
in table of operator procedures and returns its procedure and True
, if token is not found it returns False
.
Function FindAsmTokenInTable (Table: POperatorProc; Var ExpressionProc: TExpressionProc): Boolean;
begin
FindAsmTokenInTable := False;
While Ord (Table^.Token) <> 0 do
begin
If Table^.Token = AsmToken then
begin
ExpressionProc := Table^.Proc;
GetNextAsmToken;
FindAsmTokenInTable := True;
Exit;
end;
Inc (Table);
end;
end;