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 [.bss] 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 INCLUDEHEAD euroasm.htm, \ Interface (structures, symbols and macros) of other modules used in this source. chunk.htm,ctx.htm,dict.htm,ea.htm,eaopt.htm,exp.htm,lst.htm,msg.htm,pgm.htm, \ pgmopt.htm,reloc.htm,sss.htm,stm.htm,sym.htm,var.htm
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. .MemPeakPgm D D ; Memory allocated by Pgm.Pool. .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 MOV EDI,%EaPoolSize PoolCreate Size=EDI, ErrorHandler=EaMallocError:: JC .90: MOV [Src.Pool],EAX LEA EBX,[Ea.SrcFile::] LEA EDI,[EBX+FILE.Name] CMPW [EDI],'./' JNE .10: LEA ESI,[EDI+2] MOV ECX,SIZE#FILE.Name-2 REP MOVSB .10: ; Derive default program name Src.FsSrcName from the source filename. LEA ESI,[EBX+FILE.Name] FileNameParse ESI MOV ESI,EAX SUB ECX,ESI ; 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 [Src.Pool],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. MOV EDX,[Src.Pool] 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. MOV ECX,[Src.FsSrcNameSize] ; Create chunk contents on Src.Pool. 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] ; "./source.asm" instead of "source.asm" in Linux version. CMPW [EDX],'./' JNE .20: INC EDX,EDX .20: SysOpenFileMap EAX,EDX .30: Msg cc=C,'8030',EDX ; Error reading source !1$. JC .90: ; The main source file contents is now mapped in memory ESI,EAX. MOV ECX,[ESI] AND ECX,0x00FFFFFF ; Mask off the 4th byte. CMP ECX,0x00BFBBEF ; Is it UTF-8 BOM? JNE .40: ADD ESI,3 ; Ignore BOM. SUB EAX,3 JBE .30: ; Source file is too short. .40: 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.SubSize::] JECXZ .60: ; If no suboperation requested. MOV EAX,[Ea.SubPtr::] ADD ECX,EAX ; EAX..ECX now specifies the string, say {1..%&-80}[10..99] .50: Invoke ChunkSuboperate::,EBX,EAX,ECX,1 JC .90: JZ .50: ; If chunk was suboperated, more chained suboperations may follow. .60: ListStore [Src.ChunkList],EBX MOV ECX,[Src.FsSrcNameSize] ; Now create chunk Nr.3: 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 the 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 .70: SetSt [EDX+FILE.Status],fileStFound Msg '0170',EDI ; Assembling local option file "!1S". ADD EAX,ESI Invoke EaIniAssemble:: ,ESI,EAX, Src.Eaopt, Src.Pgmopt SysCloseFile EDX .70: CopyTo Ea.Eaopt::,Src.Eaopt,Size=SIZE#EAOPT Msg '0180',Ea.SrcFile.Name, Ea.SubPtr:: ; Assembling source file "!1$"!2S. .90: 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: SrcDestroy.WriteStreamBlock PROC ; Callback from StreamDump macro. ADD [%LstSize],ECX FileWrite Src.LstFile,ESI,ECX RET ENDP SrcDestroy.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.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. ADD EAX,[Src.MemPeakPgm] MOV [%ReturnEAX],EAX .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.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 .50: JE .40: .30: ListGetNext EAX JMP .10 .40: ListGetNext EAX ; TxtPtr was at the top of current chunk, lets start at the bottom of the next one. JZ .EndSource: MOV EDI,[EAX+CHUNK.Bottom] .50: MOV [%ReturnEDX],EAX ; EAX=actual chunk; EDI=start of physical line MOV ECX,[EAX+CHUNK.Top] MOV ESI,EDI SUB ECX,EDI JZ .40: JNSt [EAX+CHUNK.Status],chunkBin|chunkError,.60: MOV ECX,[EAX+CHUNK.Top] ; Chunk EAX does not contain source lines but binary data or Msg parameter. MOV [%ReturnESI],EDI MOV [%ReturnEAX],ECX JMP .NormalOutput: .60: MOV AL,10 REPNE SCASB ; Find the end of physical line. MOV [%ReturnESI],ESI MOV [%ReturnEAX],EDI MOV ECX,EDI ; Physical line ESI..EDI is specified. Now strip off comments. MOV EDI,ESI SUB ECX,ESI .70: LODSB ; Skip leading white spaces in the line of text. 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,flagZ ; ZF=1, CF=0 JMPS .90: .EndSource: MOV AH,flagZ+flagC ; ZF=CF=1 JMPS .90: .NormalOutput: MOV AH,0 ; 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 ; Diagnostic info how was the statement parsed. .18:Invoke StmExecute::,EBX ; Execute the statement: fill statement buffers, modify context stack, create symbols etc. XOR ECX,ECX XOR EAX,EAX .20:Invoke CtxPeek::,ctxPROGRAM,EAX ; Find emitting program context. JC .30: ; Skip when 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: ; It should be empty. 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 MOV [%ReturnEDX],ESI STC JMP .90: SrcPosition.TryFileEAX: PROC ; Check if LinePtr=EBX is in the 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 ; Compare EBX=LinePtr with the top of source. CMC .T9:RET ENDP SrcPosition.TryFileEAX: .Found: MOV EDX,EAX ; ^FILE. MOV [%ReturnEDX],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 ; Match with LinePtr? 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