Src represents one source file which is assembled by €ASM.
As there can be only one source being assembled at the moment, the object Src is defined statically in [.data] segment.
Src has its own memory pool.
The input source file name and its suboperation are provided by Ea.SrcFile and Ea.SubPtr.
SrcAssemble is invoked by EaAssemble
with the source file name specified in Ea.SrcFile
. Path of source filename is also used to locate the local option file euroasm.ini
and to locate the listing file, which will have the same filename as source
but appended with extension .lst
.
src PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32 EUROASM LISTINCLUDE=OFF INCLUDEHEAD "euroasm.htm" ; Interface (structures, symbols and macros) of other modules.
src HEAD ; Start of module interface.
SRC STRUC ; +00h.
.FsSrcNamePtr D D ; Pointer to a string with default (envelope) program name derived from source filename.
.FsSrcNameSize D D ; Default program name size.
.Errorlevel D D ; Highest errorlevel reached in this source.
.Inclusions D D ; Number of succesfull INCLUDE* statements in this source.
; +10h.
.Pool D D ; Src's memory pool.
.CtxStack D D ; ^STACK of context.
.EaoptStack D D ; ^STACK of EAOPT maintained with EUROASM PUSH/POP.
.HeadStack D D ; ^STACK of CHUNK_HEAD for nested HEAD/ENDHEAD blocks.
; +20h.
.VarList D D ; ^LIST of %variables.
.ChunkList D D ; ^LIST of source chunks.
.FileList D D ; ^LIST of FILEs included in this source.
.PfList D D ; ^LIST of QWORDS (Ptr,Size) of output file names (used for detection of W3990).
; +30h.
.CurrentStm D D ; ^STM currently executed. Used in MsgProc.
.Lst DS LST ; Listing object.
.Eaopt DS EAOPT ; Current €ASM options in charge.
.Pgmopt DS PGMOPT ; Current program options used as default.
.IniFile DS FILE ; Local option file.
.LstFile DS FILE ; Listing file.
ENDSTRUC SRC
ENDHEAD src ; End of module interface.
[.bss] Src:: DS SRC ; The source object. [.text]
euroasm.ini, if found.
SrcCreate Procedure
Chunk LocalVar Size=SIZE#CHUNK
FileName$ LocalVar Size=MAX_PATH_SIZE ; Room for local euroasm.ini filename.
; Initialize memory pool.
Clear Src
PoolCreate Size=%EaPoolSize, ErrorHandler=EaMallocError::
JC .99:
MOV [Src.Pool],EAX
MOV EDX,EAX
; Derive default program name Src.FsSrcName from source filename.
LEA ESI,[Ea.SrcFile.Name::]
MOV ECX,[Ea.SrcFile.ExtOffs::]
ADD ESI,[Ea.SrcFile.NameOffs::]
SUB ECX,[Ea.SrcFile.NameOffs::]
; ESI,ECX is now source file name without path and extension.
Invoke EaBufferReserve::,SrcCreate
Invoke EaFs2Id::,ESI,ECX,EAX ; Create an identifier from file name.
BufferRetrieve EAX
Invoke EaBufferRelease::,EAX
PoolStore EDX,ESI,ECX ; Permanently store derived name ESI,ECX.
MOV [Src.FsSrcNamePtr],EAX ; Will be used as default (envelope) program name.
MOV [Src.FsSrcNameSize],ECX
; Create memory structures of the source on source pool EDX.
StackCreate EDX,SIZE#CTX,Depth=32
MOV [Src.CtxStack],EAX
StackCreate EDX,SIZE#EAOPT,Depth=4
MOV [Src.EaoptStack],EAX
StackCreate EDX,SIZE#CHUNK_HEAD,Depth=4
MOV [Src.HeadStack],EAX
ListCreate EDX,SIZE#VAR
MOV [Src.VarList],EAX
ListCreate EDX,8
MOV [Src.PfList],EAX ; Output file names are kept here.
ListCreate EDX,SIZE#CHUNK
MOV [Src.ChunkList],EAX
ListCreate EDX,SIZE#FILE
MOV [Src.FileList],EAX ; Included files are kept in Src.FileList.
Invoke LstCreate:: ; Initialize Src.Lst object.
; Three chunks will initialize assembly:
; 1. "FsSrcName: PROGRAM" stored on Src.Pool (chunkEnvelope).
; 2. contents of base source file mapped in memory (chunkSource).
; 3. "ENDPROGRAM FsSrcName:" stored in Src.Pool (chunkEnvelope).
; First create chunk Nr.1:
LEA EBX,[%Chunk]
LEA EAX,[Ea.SrcFile::]
MOV [EBX+CHUNK.FilePtr],EAX ; The main source.
; Create chunk contents on Src.Pool.
MOV ECX,[Src.FsSrcNameSize]
LEA EDX,[ECX+11]
PoolNew [Src.Pool],EDX, Align=BYTE
MOV EDI,EAX ; Room for envelope PROGRAM statement.
MOV [EBX+CHUNK.Bottom],EAX
MOV ESI,[Src.FsSrcNamePtr]
REP MOVSB
MOV AX,": "
STOSW
MOV ESI,[Dict_PseudoPROGRAM::+DICT.Ptr] ; The text "PROGRAM".
MOV ECX,[Dict_PseudoPROGRAM::+DICT.Size]
REP MOVSB
MOV AX,0x0A0D ; CR+LF.
STOSW
MOV [EBX+CHUNK.Top],EDI
MOVD [EBX+CHUNK.Status],chunkEnvelope
ListStore [Src.ChunkList],EBX
; Create chunk Nr.2:
LEA EBX,[%Chunk]
MOV EAX,[EBX+CHUNK.FilePtr]
LEA EDX,[EAX+FILE.Name]
SysOpenFileMap EAX,EDX
Msg cc=C,'8030',EDX ; Error reading source !1$.
JC .99:
; The main source file contents is now mapped in memory ESI,EAX.
MOV [EBX+CHUNK.Bottom],ESI
ADD EAX,ESI
MOV [EBX+CHUNK.Top],EAX
MOVD [EBX+CHUNK.Status],chunkSource
; Source file might have been specified with suboperation, e.g. "source.asm"{1..%&-80}[10..99]
MOV ECX,[Ea:: + EA.SubSize]
JECXZ .30: ; If no suboperation requested.
MOV EAX,[Ea:: + EA.SubPtr]
ADD ECX,EAX ; EAX..ECX now specifies string e.g. {1..%&-80}[10..99]
.20: Invoke ChunkSuboperate::,EBX,EAX,ECX,1
JC .99:
JZ .20: ; If chunk was suboperated, more chained suboperations may follow.
.30: ListStore [Src.ChunkList],EBX
; Now create chunk Nr.3:
MOV ECX,[Src.FsSrcNameSize]
LEA EDX,[ECX+13]
PoolNew [Src.Pool],EDX, Align=BYTE
MOV EDI,EAX
MOV [EBX+CHUNK.Bottom],EAX
MOV ESI,[Dict_PseudoENDPROGRAM::+DICT.Ptr] ; The text "ENDPROGRAM".
MOV ECX,[Dict_PseudoENDPROGRAM::+DICT.Size] ; 9.
REP MOVSB
MOV AL,' '
STOSB
MOV ESI,[Src.FsSrcNamePtr]
MOV ECX,[Src.FsSrcNameSize]
REP MOVSB
MOV AL,':'
STOSB
MOV AX,0x0A0D ; CR+LF.
STOSW
MOV [EBX+CHUNK.Top],EDI
MOVD [EBX+CHUNK.Status],chunkEnvelope
ListStore [Src.ChunkList],EBX
; Current options are inherited from parent object (Ea).
CopyTo Src.Eaopt, Ea.EaoptIni::
CopyTo Src.Pgmopt, Ea.Pgmopt::
; Then the options will be updated from local euroasm.ini file, if found.
MOV ESI,Ea.SrcFile.Name::
MOV ECX,[Ea.SrcFile.NameOffs::]
LEA EDI,[%FileName$]
PUSH EDI
REP MOVSB ; Concantenate source path and "euroasm.ini".
MOV ESI,=B"euroasm.ini"
MOV ECX,12
REP MOVSB
POP EDI
MOV EDX,Src.IniFile
SysOpenFileMap EDX,EDI
Msg cc=C,'0160',EDI ; Local option file "!1$" was not found.
JC .60:
SetSt [EDX+FILE.Status],fileFound
Msg '0170',EDI ; Assembling local option file "!1S".
ADD EAX,ESI
Invoke EaIniAssemble:: ,ESI,EAX, Src.Eaopt, Src.Pgmopt
SysCloseFile EDX
.60: CopyTo Ea.Eaopt::,Src.Eaopt,Size=SIZE#EAOPT
Msg '0180',Ea.SrcFile.Name::, Ea.SubPtr:: ; Assembling source file "!1$"!2S.
.99: EndProcedure SrcCreate
SrcDestroy Procedure
LstSize LocalVar
Invoke LstGetFileName::
LEA EBX,[Src.LstFile]
SysAssignFile EBX,ESI,ECX
FileMkDir EBX
JNC .30:
.LstError:
LEA EAX,[EBX+FILE.Name]
Msg '7982',EAX ; Error writing to listing file "!1$".
JMP .40:
.WriteStreamBlock PROC ; Callback from StreamDump macro.
ADD [%LstSize],ECX
FileWrite Src.LstFile,ESI,ECX
RET
ENDP .WriteStreamBlock
.30: FileCreate EBX ; Write listing to ListFile.
JC .LstError:
MOVD [%LstSize],0 ; File size counter.
LEA EDX,[Src.Lst]
StreamDump [EDX+LST.Stream], .WriteStreamBlock
JC .LstError:
LEA EAX,[EBX+FILE.Name]
Msg '0860',EAX,[%LstSize] ; Listing file "!1$" created, size=!2D.
.40: FileClose EBX ; Close the listing file.
.50: CopyTo Ea.Eaopt::, Src.Eaopt, Size=SIZE#EAOPT ; Ea.Eaopt is updated from Src.Eaopt.
ListGetLast [Src.FileList]
JZ .80:
.70: SysCloseFile EAX ; Close all included files.
ListGetPrev EAX
JNZ .70:
SysCloseFile Ea::+EA.SrcFile ; Close the base source file.
.80: MOV EDX,[Src.Pool]
MOV [Src.CtxStack],0
PoolDestroy EDX
Msg cc=C,'2575','Src',EDX ; Deallocation of virtual memory !1C.Pool !2Hh failed.
.90: Clear Src
EndProcedure SrcDestroy
chunkBin or
chunkError, the returned data ESI..EAX is not source line
but binary data or Msg parameter. The caller should test chunk status first.
SrcFetchLine Procedure LinePtr, ChunkPtr
MOV EAX,[%ChunkPtr]
MOV EDI,[%LinePtr]
TEST EAX
JNZ .10:
ListGetFirst [Src + SRC.ChunkList]
.10: JZ .EndSource: ; No more chunks.
TEST EDI
JNZ .20:
MOV EDI,[EAX+CHUNK.Bottom]
.20: CMP EDI,[EAX+CHUNK.Bottom]
JB .30:
CMP EDI,[EAX+CHUNK.Top]
JB .60:
JE .40:
.30: ListGetNext EAX
JMP .10
.40: ; TxtPtr was at the top of current chunk, lets start at the bottom of the next one.
.50: ListGetNext EAX
JZ .EndSource:
MOV EDI,[EAX+CHUNK.Bottom]
.60: ; EAX=actual chunk; EDI=start of physical line
MOV [%ReturnEDX],EAX
MOV ECX,[EAX+CHUNK.Top]
MOV ESI,EDI
SUB ECX,EDI
JZ .50:
JNSt [EAX+CHUNK.Status],chunkBin|chunkError,.65:
; Chunk EAX does not contain source lines but binary data or Msg parameter.
MOV ECX,[EAX+CHUNK.Top]
MOV [%ReturnESI],EDI
MOV [%ReturnEAX],ECX
JMP .NormalOutput:
.65: MOV AL,10
REPNE SCASB ; Find the end of physical line.
MOV [%ReturnESI],ESI
MOV [%ReturnEAX],EDI
; Pysical line ESI..EDI is specified. Now strip off comments.
MOV ECX,EDI
MOV EDI,ESI
SUB ECX,ESI
.70: LODSB ; Skip leading white spaces on line.
DEC ECX
JZ .NormalOutput:
ExpClassify AL
TEST AH,expWhiteSpace
JNZ .70:
CMP AL,'<' ;>
JE .CommentOnly:
CMP AL,'|'
JNE .NormalOutput:
MOV EDI,ESI
REPNE SCASB
MOV [%ReturnESI],EDI
JE .NormalOutput:
.CommentOnly:
MOV AH,01000000b ; ZF=1, CF=0
JMPS .90:
.EndSource:
MOV AH,01000001b ; ZF=CF=1
JMPS .90:
.NormalOutput:
MOV AH,00000000b ; ZF=CF=0
.90: SAHF
EndProcedure SrcFetchLine
SrcAssemble Procedure
Stm LocalVar Size=SIZE#STM ; Stm object used for statement parsing.
LEA EBX,[%Stm]
Invoke StmCreate::,EBX
SUB EDX,EDX
SUB EAX,EAX ; LinePtr=0, start with the 1st line of source, which is envelope "file: PROGRAM".
.10: ; Here is the main loop which will read and execute all statements in the source.
Invoke StmClean::,EBX ; Empty statement buffers and erase remains of previous statement.
MOV [Src.CurrentStm],EBX
Invoke StmParse::,EBX,EAX,EDX ; Fetch and parse statement adressed with EAX.
JC .60: ; If no more source lines.
INCD [Ea.StmCount::] ; Counter of total assembled statements.
JNSt [Ea.Eaopt.Status::],eaoptDISPLAYSTM,.18:
Invoke StmDisplayParsed::,EBX
.18:Invoke StmExecute::,EBX ; Execute the statement: fill statement buffers, modify context stack, create symbols etc.
SUB ECX,ECX
SUB EAX,EAX
.20:Invoke CtxPeek::,ctxPROGRAM,EAX ; Find emitting program context.
JC .30: ; If envelope ENDPROGRAM was just executed. No more programs on stack.
MOV ECX,[EAX+CTX.ObjPtr] ; ECX=0 when PROGRAM statement was in NoEmit state.
JECXZ .20: ; If NoEmit, search the stack deeper.
JNSt [ECX+PGM.Status],pgmLastPass,.50: ; Skip the listing in nonlast passes.
JSt [ECX+PGM.Status],pgmLastJustSet,.40:
.30: Invoke StmListing::,EBX ; Create a listing line(s) and write to Lst.Stream.
.40: JECXZ .50:
RstSt [ECX+PGM.Status],pgmLastJustSet
.50: RstSt [Src.Lst.Status],lstVolMask ; Clear used volatile flags of listing.
Invoke StmFlush::,EBX ; Flush STM.EmitBuffer to the current section's SSS.EmitBuffer.
CMP [Src.Errorlevel],8
JAE .80: ; Abort if source fatal error. The source file will be prematurely abandoned.
MOV EAX,[EBX+STM.LineNext] ; The next statement where to continue.
MOV EDX,[EBX+STM.ChunkNext]
TEST EAX
JNZ .10: ; If STM.LineNext is specified, go to assemble this new statement (macro or repeat block).
; Otherwise continue with the next statement in the normal source flow.
MOV EAX,[EBX+STM.LineEnd] ; End of just executed statement is the beginning of the next one.
MOV EDX,[EBX+STM.ChunkPtr]
JMP .10:
.60: ; End of source text.
StackPop [Src.CtxStack] ; Check if no context was left on stack.
JC .80: ; If stack empty, OK.
MOV EDI,EAX ; Some block in source was left open, this is an error.
Invoke CtxGetEndTypename::,[EDI+CTX.Status] ; EAX=^DQ Ptr,Size
JNSt [EDI+CTX.Status],ctxREPEAT,.70:
JSt [EDI+CTX.Status],ctxExited,.70:
XCHG EAX,EDI ; Operation %REPEAT has block identifier in %1 instead of label field.
.70: Msg '7110',EAX,EDI ; Wrong nesting, expected !1S !2S. ENDblock id
JMP .60:
.80: Invoke StmDestroy::,EBX
MOVD [Src.CurrentStm],0
.90: EndProcedure SrcAssemble
SrcPosition Procedure LinePtr
MOV EBX,[%LinePtr]
MOV EAX,Ea.SrcFile::
CALL .TryFileEAX:
JNC .Found:
ListGetFirst [Src.FileList]
JZ .20:
.10:CALL .TryFileEAX:
JNC .Found:
ListGetNext EAX
JNZ .10:
.20:MOV EAX,Ea.IniFile:: ; Try global "euroasm.ini".
CALL .TryFileEAX:
JNC .Found:
MOV EAX,Src.IniFile ; Try local "euroasm.ini".
CALL .TryFileEAX:
MOV EDI,=B(0) ; No source file found.
SUB ESI,ESI
STC
JMP .90:
.TryFileEAX: PROC ; Check if LinePtr=EBX is in mapped range of file EAX.
; Output: CF=1 if not in range. ECX=?
MOV ECX,[EAX+FILE.BufPtr] ; Bottom of mapped source.
CMP EBX,ECX
JB .T9:
ADD ECX,[EAX+FILE.BufSize] ; Top of mapped source.
CMP EBX,ECX
CMC
.T9:RET
ENDP .TryFileEAX:
.Found:
MOV EDX,EAX ; ^FILE.
MOV EDI,[EDX+FILE.BufPtr]
MOV ECX,[EDX+FILE.BufSize]
SUB ESI,ESI ; Line counter.
MOV AL,10 ; End of physical line.
.60:INC ESI
JECXZ .80:
REPNE SCASB ; Find EOL.
CMP EBX,EDI
JAE .60:
.80:LEA EDI,[EDX+FILE.Name]
ADD EDI,[EDX+FILE.NameOffs] ; Skip file path, if any. CF=0.
.90:MOV [%ReturnEDI],EDI
MOV [%ReturnEAX],ESI
EndProcedure SrcPosition
ENDPROGRAM src