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.
Processing of assembler expressions:Procedure ProcessAsmExpressionAndCheck; begin CheckAsmStack; ClearLeftExpression; ProcessAsmExpression; With LeftExpression^ do If (Token = AsmToken_MemoryReference) and not (mrMemoryLocation in MemoryReferences) then AsmError (MemoryReferenceExpected); end;
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; Processing of factor elements in assembler expression:
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; Processing of factors in assembler expression for the following operations:
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:
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; |