Processing Assembler Expressions
Assembler expressions (instruction parameters) are processed similarly to Pascal expressions. The expression is divided into smaller parts according to the operator precedence. For assembler expressions Turbo Pascal uses few data structures and procedures. TAsmExpression
contains fields that hold data for each expression (instruction parameter).
Type TRegisterType = (rt8BitRegister, rt16BitRegister, rtSegmentRegister, rt03, rtFPURegister);
TMemoryReferenceRegisters = (mrDI, mrSI, mrBP, mrBX, mr10, mr20, mrMemoryLocation, mr80);
TMemoryReferenceRegistersSet = Set of TMemoryReferenceRegisters;
PAsmValue = ^TAsmValue;
TAsmValue = Record
Case Byte of
0: (LongInt: LongInt);
1: (Word, Word2: Word);
2: (Byte, Byte1, Byte2, Byte3: Byte);
end;
PAsmExpression = ^TAsmExpression;
TAsmExpression = Record
Value: TAsmValue;
AdditionalIdentifierData: Pointer;
RelocatableIdentifier: LongInt;
TypeSize: Word;
MemoryReferences: TMemoryReferenceRegistersSet;
SegmentOverrideOpcode: Byte;
RegisterType: TRegisterType;
Register: Byte;
Token: TAsmToken;
ReferenceFlags: Byte;
end;
Assembler instructions can have up to three comma-separated parameters.
Procedure ProcessInstructionExpresions;
begin
ExpressionCounter := 0;
ErrorPositionInstructionExpresion1 := AsmSourceErrorPosition;
If CheckAndGetNextAsmToken (AsmToken_Semicolon) then Exit;
LeftExpression := @AsmExpression1;
ProcessAsmExpressionAndCheck;
Inc (ExpressionCounter);
If CheckAndGetNextAsmToken (AsmToken_Semicolon) then Exit;
ExpectAsmTokenAndGetNext (AsmToken_Comma);
ErrorPositionInstructionExpresion2 := AsmSourceErrorPosition;
LeftExpression := @AsmExpression2;
ProcessAsmExpressionAndCheck;
Inc (ExpressionCounter);
LeftExpression := @AsmExpression1;
RightExpression := @AsmExpression2;
SavedRightExpressionTypeSize := RightExpression^.TypeSize;
If RightExpression^.TypeSize <> 0 then
begin
If LeftExpression^.TypeSize = 0 then LeftExpression^.TypeSize := RightExpression^.TypeSize;
end else RightExpression^.TypeSize := LeftExpression^.TypeSize;
If CheckAndGetNextAsmToken (AsmToken_Semicolon) then Exit;
ExpectAsmTokenAndGetNext (AsmToken_Comma);
LeftExpression := @AsmExpression3;
ProcessAsmExpressionAndCheck;
Inc (ExpressionCounter);
ExpectAsmTokenAndGetNext (AsmToken_Semicolon);
end;
This procedure processes assembler expression and checks for valid memory reference.
Procedure ProcessAsmExpressionAndCheck;
begin
CheckAsmStack;
ClearLeftExpression;
ProcessAsmExpression;
With LeftExpression^ do
If (Token = AsmToken_MemoryReference) and not (mrMemoryLocation in MemoryReferences)
then AsmError (MemoryReferenceExpected);
end;
Processing of assembler expressions:
SimpleTerm
SimpleTerm
ORSimpleTerm
SimpleTerm
XORSimpleTerm
Procedure OR_Proc; Far;
begin
LeftExpression^.Value.LongInt := LeftExpression^.Value.LongInt or RightExpression^.Value.LongInt;
end;
Procedure XOR_Proc; Far;
begin
LeftExpression^.Value.LongInt := LeftExpression^.Value.LongInt xor RightExpression^.Value.LongInt;
end;
Procedure ProcessAsmExpression;
Const OR_XOR_Table: TOperatorProc = (Token: AsmToken_OR; Proc: OR_Proc);
OR_XOR_Table1: TOperatorProc = (Token: AsmToken_XOR; Proc: XOR_Proc);
OR_XOR_Table_End: Byte = 0;
Var ExpressionProc: TExpressionProc;
begin
ProcessAsmTerm;
While FindAsmTokenInTable (@OR_XOR_Table, ExpressionProc) do
begin
CheckConstantExpression;
PushLeftAndCreateNewExpression (ExpressionProc);
ProcessAsmTerm;
CheckConstantExpression;
MoveLastExpressionToRightAndPopLeftExpression (ExpressionProc);
ExpressionProc;
Asm
ADD SP, 20
end;
end;
end;
SimpleAsmTerm
SimpleAsmTerm
ANDSimpleAsmTerm
Processing of simple assembler term for operators:
-
NOT
-
+
-
-
Procedure Plus_Proc; Far;
begin
AddAsmExpressions;
AsmString := '';
end;
Procedure Minus_Proc; Far;
begin
SwapLeftAndRightExpression;
CheckNoRelocatableIdentifier;
SwapLeftAndRightExpression;
RightExpression^.Value.LongInt := - RightExpression^.Value.LongInt;
AddAsmExpressions;
AsmString := '';
end;
Procedure ProcessAsmTerm;
Var ExpressionProc: TExpressionProc;
Procedure Process_NOT_PLUS_MINUS;
Const NOT_Table: TOperatorProc = (Token: AsmToken_NOT; Proc: nil);
NOT_Table_End: Byte = 0;
PlusMinus_Table: TOperatorProc = (Token: AsmToken_Plus; Proc: Plus_Proc);
PlusMinus_Table1: TOperatorProc = (Token: AsmToken_Minus; Proc: Minus_Proc);
PlusMinus_Table_End: Byte = 0;
Var ExpressionProc: TExpressionProc;
begin
CheckAsmStack;
If FindAsmTokenInTable (@NOT_Table, ExpressionProc) then
begin
Process_NOT_PLUS_MINUS;
CheckConstantExpression;
LeftExpression^.Value.LongInt := not LeftExpression^.Value.LongInt;
AsmString := '';
Exit;
end;
ProcessAsmFactor;
While FindAsmTokenInTable (@PlusMinus_Table, ExpressionProc) do
begin
PushLeftAndCreateNewExpression (ExpressionProc);
ProcessAsmFactor;
MoveLastExpressionToRightAndPopLeftExpression (ExpressionProc);
ExpressionProc;
Asm
ADD SP, 20
end;
end;
end;
begin
Process_NOT_PLUS_MINUS;
While CheckAndGetNextAsmToken (AsmToken_AND) do
begin
CheckConstantExpression;
PushLeftAndCreateNewExpression (ExpressionProc);
Process_NOT_PLUS_MINUS;
CheckConstantExpression;
MoveLastExpressionToRightAndPopLeftExpression (ExpressionProc);
LeftExpression^.Value.LongInt := LeftExpression^.Value.LongInt and RightExpression^.Value.LongInt;
Asm
ADD SP, 20
end;
end;
end;
This procedure reports error if expression is not constant.
Procedure CheckConstantExpression;
begin
If (LeftExpression^.Token <> AsmToken_Constant) or (LeftExpression^.RelocatableIdentifier <> 0) then
AsmError (ConstantExpected);
end;
*
/
DIV
MOD
SHR
SHL
Procedure Asterisk_Proc; Far;
begin
LeftExpression^.Value.LongInt := LeftExpression^.Value.LongInt * RightExpression^.Value.LongInt;
end;
Procedure Slash_Proc; Far;
begin
If RightExpression^.Value.LongInt = 0 then AsmError (DivisionByZero);
LeftExpression^.Value.LongInt := LeftExpression^.Value.LongInt div RightExpression^.Value.LongInt;
end;
Procedure MOD_Proc; Far;
begin
If RightExpression^.Value.LongInt = 0 then AsmError (DivisionByZero);
LeftExpression^.Value.LongInt := LeftExpression^.Value.LongInt mod RightExpression^.Value.LongInt;
end;
Procedure SHR_Proc; Far;
begin
LeftExpression^.Value.LongInt := LeftExpression^.Value.LongInt shr RightExpression^.Value.LongInt;
end;
Procedure SHL_Proc; Far;
begin
LeftExpression^.Value.LongInt := LeftExpression^.Value.LongInt shl RightExpression^.Value.LongInt;
end;
Procedure ProcessAsmFactor;
Const MultDivShift_Table: TOperatorProc = (Token: AsmToken_Asterisk; Proc: Asterisk_Proc);
MultDivShift_Table1: TOperatorProc = (Token: AsmToken_Slash; Proc: Slash_Proc);
MultDivShift_Table2: TOperatorProc = (Token: AsmToken_MOD; Proc: MOD_Proc);
MultDivShift_Table3: TOperatorProc = (Token: AsmToken_SHR; Proc: SHR_Proc);
MultDivShift_Table4: TOperatorProc = (Token: AsmToken_SHL; Proc: SHL_Proc);
MultDivShift_Table_End: Byte = 0;
Var ExpressionProc: TExpressionProc;
begin
ProcessAsmFactorElement;
While FindAsmTokenInTable (@MultDivShift_Table, ExpressionProc) do
begin
CheckConstantExpression;
PushLeftAndCreateNewExpression (ExpressionProc);
ProcessAsmFactorElement;
CheckConstantExpression;
MoveLastExpressionToRightAndPopLeftExpression (ExpressionProc);
ExpressionProc;
Asm
ADD SP, 20
end;
end;
end;
Processing of factor element in assembler expression:
QualifiedExpressionElement
QualifiedExpressionElement
PTRAsmFactorElement
QualifiedExpressionElement
:AsmFactorElement
Processing of qualified basic expression element:
- Unary
+
, – HIGH
,LOW
- Basic expression element
- Qualifiers
.
,(
,[
Procedure OFFSET_Proc; Far;
begin
With LeftExpression^ do
begin
ReferenceFlags := 1;
Token := AsmToken_Constant;
MemoryReferences := [];
SegmentOverrideOpcode := 0;
Value.Word2 := 0;
TypeSize := 0;
If RelocatableIdentifier = 0 then ReferenceFlags := 0;
end;
end;
Procedure SEG_Proc; Far;
begin
With LeftExpression^ do
begin
ReferenceFlags := 2;
Value.Word := LeftExpression^.Value.Word2;
Token := AsmToken_Constant;
MemoryReferences := [];
SegmentOverrideOpcode := 0;
Value.Word2 := 0;
TypeSize := 0;
If RelocatableIdentifier = 0 then ReferenceFlags := 0;
end;
end;
Procedure TYPE_Proc; Far;
begin
With LeftExpression^ do
begin
Value.Word := LeftExpression^.TypeSize;
RelocatableIdentifier := 0;
Token := AsmToken_Constant;
MemoryReferences := [];
SegmentOverrideOpcode := 0;
Value.Word2 := 0;
TypeSize := 0;
If RelocatableIdentifier = 0 then ReferenceFlags := 0;
end;
end;
Procedure UnaryPlus_Proc; Far;
begin
AsmString := '';
end;
Procedure UnaryMinus_Proc; Far;
begin
CheckNoRelocatableIdentifier;
LeftExpression^.Value.LongInt := - LeftExpression^.Value.LongInt;
AsmString := '';
end;
Procedure HIGH_Proc; Far;
begin
LeftExpression^.Value.LongInt := LeftExpression^.Value.Byte1;
end;
Procedure LOW_Proc; Far;
begin
LeftExpression^.Value.LongInt := LeftExpression^.Value.Byte;
end;
Procedure ProcessAsmFactorElement;
Const OFFSET_SEG_TYPE_Table: TOperatorProc = (Token: AsmToken_OFFSET; Proc: OFFSET_Proc);
OFFSET_SEG_TYPE_Table1: TOperatorProc = (Token: AsmToken_SEG; Proc: SEG_Proc);
OFFSET_SEG_TYPE_Table2: TOperatorProc = (Token: AsmToken_TYPE; Proc: TYPE_Proc);
OFFSET_SEG_TYPE_Table_End: Byte = 0;
Var SegmentRegister: Byte;
Saved_TypeSize: Word;
Saved_LeftExpression_AdditionalIdentifierData: Pointer;
NumberOfPushedProcs: Word;
ExpressionProc, TempExpressionProc: TExpressionProc;
Procedure ProcessQualifiedBasicExpressionElement;
Const UnaryPlusMinus_Table: TOperatorProc = (Token: AsmToken_Plus; Proc: UnaryPlus_Proc);
UnaryPlusMinus_Table1: TOperatorProc = (Token: AsmToken_Minus; Proc: UnaryMinus_Proc);
UnaryPlusMinus_Table_End: Byte = 0;
HIGH_LOW_Table: TOperatorProc = (Token: AsmToken_HIGH; Proc: HIGH_Proc);
HIGH_LOW_Table1: TOperatorProc = (Token: AsmToken_LOW; Proc: LOW_Proc);
HIGH_LOW_Table_End: Byte = 0;
Var NumberOfPushedProcs: Word;
ExpressionProc, TempExpressionProc: TExpressionProc;
begin
NumberOfPushedProcs := 0;
While FindAsmTokenInTable (@UnaryPlusMinus_Table, ExpressionProc) do
begin
CheckAsmStack;
Asm
PUSH WORD PTR ExpressionProc + 2
PUSH WORD PTR ExpressionProc
end;
Inc (NumberOfPushedProcs);
end;
While FindAsmTokenInTable (@HIGH_LOW_Table, ExpressionProc) do
begin
CheckAsmStack;
Asm
PUSH WORD PTR ExpressionProc + 2
PUSH WORD PTR ExpressionProc
end;
Inc (NumberOfPushedProcs);
end;
CheckAsmStack;
ProcessBasicExpressionElement;
Repeat
Case AsmToken of
AsmToken_Point: begin
AsmIdentifierAdditionalData := LeftExpression^.AdditionalIdentifierData;
LeftExpression^.AdditionalIdentifierData := nil;
GetNextAsmToken;
PushLeftAndCreateNewExpression (ExpressionProc);
ProcessAsmFactorElement;
MoveLastExpressionToRightAndPopLeftExpression (ExpressionProc);
If RightExpression^.Token = AsmToken_Register then AsmError (FieldIdentifierExpected);
If RightExpression^.TypeSize <> 0 then LeftExpression^.TypeSize := 0;
AddAsmExpressions;
Asm
ADD SP, 20
end;
end;
AsmToken_LeftBracket,
AsmToken_LeftParenthesis: begin
PushLeftAndCreateNewExpression (ExpressionProc);
ProcessBasicExpressionElement;
MoveLastExpressionToRightAndPopLeftExpression (ExpressionProc);
If LeftExpression^.TypeSize <> 0 then RightExpression^.TypeSize := 0;
AddAsmExpressions;
Asm
ADD SP, 20
end;
end;
else begin
While NumberOfPushedProcs <> 0 do
begin
Asm
POP WORD PTR TempExpressionProc
POP WORD PTR TempExpressionProc + 2
end;
TempExpressionProc;
Dec (NumberOfPushedProcs);
end;
Exit;
end;
end;
until False;
end;
begin
CheckAsmStack;
NumberOfPushedProcs := 0;
While FindAsmTokenInTable (@OFFSET_SEG_TYPE_Table, ExpressionProc) do
begin
Asm
PUSH WORD PTR ExpressionProc + 2
PUSH WORD PTR ExpressionProc
end;
Inc (NumberOfPushedProcs);
ClearLeftExpression;
end;
ProcessQualifiedBasicExpressionElement;
If CheckAndGetNextAsmToken (AsmToken_PTR) then
begin
PushLeftAndCreateNewExpression (ExpressionProc);
ProcessAsmFactorElement;
If LeftExpression^.Token = AsmToken_Register then AsmError (ConstantExpected);
MoveLastExpressionToRightAndPopLeftExpression (ExpressionProc);
Saved_TypeSize := LeftExpression^.TypeSize;
Saved_LeftExpression_AdditionalIdentifierData := LeftExpression^.AdditionalIdentifierData;
LeftExpression^ := RightExpression^;
LeftExpression^.TypeSize := Saved_TypeSize ;
LeftExpression^.AdditionalIdentifierData := Saved_LeftExpression_AdditionalIdentifierData;
LeftExpression^.Token := AsmToken_MemoryReference;
Include (LeftExpression^.MemoryReferences, mrMemoryLocation);
Asm
ADD SP, 20
end;
end else If (LeftExpression^.RegisterType = rtSegmentRegister) and
(LeftExpression^.Token = AsmToken_Register) and CheckAndGetNextAsmToken (AsmToken_Colon) then
begin
SegmentRegister := LeftExpression^.Register;
ClearLeftExpression;
ProcessAsmFactorElement;
LeftExpression^.SegmentOverrideOpcode := SegmentRegister shl 3 or SegmentOverride;
Include (LeftExpression^.MemoryReferences, mrMemoryLocation);
SetExpressionToMemoryReference;
end;
While NumberOfPushedProcs <> 0 do
begin
Asm
POP WORD PTR TempExpressionProc
POP wORD PTR TempExpressionProc + 2
end;
TempExpressionProc;
Dec (NumberOfPushedProcs);
end;
end;
Most operations are performed on constant values and processed with procedures above, however, addition is special since many different cases are possible. This procedure adds two assembler expressions.
Procedure AddAsmExpressions;
Procedure SetBothExpressionsToMemoryReference;
begin
SetExpressionToMemoryReference;
SwapLeftAndRightExpression;
SetExpressionToMemoryReference;
SwapLeftAndRightExpression;
end;
begin
If RightExpression^.Token <> AsmToken_Constant then SetBothExpressionsToMemoryReference else
If LeftExpression^.Token <> AsmToken_Constant then
Case LeftExpression^.Token of
AsmToken_Register: If LeftExpression^.RegisterType = rtFPURegister then
LeftExpression^.Register := (LeftExpression^.Register + RightExpression^.Value.Byte) and $07
else SetBothExpressionsToMemoryReference;
else SetBothExpressionsToMemoryReference;
end;
begin
LeftExpression^.Value.LongInt := LeftExpression^.Value.LongInt + RightExpression^.Value.LongInt;
If RightExpression^.AdditionalIdentifierData <> nil then
LeftExpression^.AdditionalIdentifierData := RightExpression^.AdditionalIdentifierData;
If RightExpression^.RelocatableIdentifier <> 0 then
begin
LeftExpression^.ReferenceFlags := RightExpression^.ReferenceFlags;
If LeftExpression^.RelocatableIdentifier <> 0 then AsmError (CannotAddOrSubtractRelocatableSymbols);
LeftExpression^.RelocatableIdentifier := RightExpression^.RelocatableIdentifier;
end;
If RightExpression^.TypeSize <> 0 then LeftExpression^.TypeSize := RightExpression^.TypeSize;
If (LeftExpression^.MemoryReferences *
RightExpression^.MemoryReferences * [mrBX, mrBP, mrSI, mrDI]) <> [] then AsmError (InvalidRegisterCombination);
LeftExpression^.MemoryReferences :=
LeftExpression^.MemoryReferences + RightExpression^.MemoryReferences;
If RightExpression^.SegmentOverrideOpcode <> 0 then
begin
If LeftExpression^.SegmentOverrideOpcode and $80 <> 0 then AsmError (SyntaxError);
LeftExpression^.SegmentOverrideOpcode := RightExpression^.SegmentOverrideOpcode;
end;
end;
end;
This procedure sets expression to memory reference and checks reference registers.
Procedure SetExpressionToMemoryReference;
Const MemoryReferenceRegister: Array [rAX..rDI] of TMemoryReferenceRegistersSet =
([], [], [], [mrBX], [], [mrBP], [mrSI], [mrDI]);
begin
With LeftExpression^ do
Case Token of
AsmToken_Constant: Token := AsmToken_MemoryReference;
AsmToken_Register: begin
If RegisterType <> rt16BitRegister then AsmError (InvalidRegisterCombination);
If MemoryReferenceRegister [Register] = [] then AsmError (InvalidRegisterCombination);
MemoryReferences := MemoryReferenceRegister [Register];
TypeSize := 0;
Token := AsmToken_MemoryReference;
end;
AsmToken_MemoryReference:
else AsmError (MemoryReferenceExpected);
end;
end;
This procedure swaps left and right assembler expression (only pointers are swapped).
Procedure SwapLeftAndRightExpression;
Var TempExpression: PAsmExpression;
begin
TempExpression := LeftExpression;
LeftExpression := RightExpression;
RightExpression := TempExpression;
end;