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 EUROASM LISTINCLUDE=OFF INCLUDEHEAD "euroasm.htm" ; Interface (structures, symbols and macros) of other modules. INCLUDEHEAD \ ; Include headers of another modules used in this module. 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, \ syswin.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. .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],fileStFound 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: 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. .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 ; Pysical 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 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 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 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