New/rewritten December 2016
The List File compiler option—/LF for COMPIL.LIT, -lf for the standalone compiler—generates a consolidated list file showing all of the source code, with all of the ++include files merged in. The list file is known as the "LSX file" (LiSt with indeX), is named <prog>.LSX, and is created in the same directory as the main program source. Some of its attributes and uses are detailed in the comments below.
Standalone Recompilability
Since the LSX file contains all of the source code merged in from all the ++include statements, it effectively captures the entire state of the source code at the time it was compiled, and thus provides an easy way to archive the source corresponding to a particular RUN or SBX module released. The top of the LSX file indicates the compiler version and switches, which you can use to regenerate the compiled output directly from the LSX file. For example, the LSX file for a program named ASHDEVINF.BP may contain the following at the top...
Command line args >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/av /i /x:2 /lf /p /m [Ver: 6.3(788)]
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
000000 PROGRAM ashdevinf.bp,1.0 (102)
000000
...
To recompile the LSX, just specify the LSX extension along with the original switches, i.e.
.compil ashdevinf.lsx/av/i/x:2/lf/p/m
Note that you probably don't need to specify the /lf switch again, since you already have the LSX file, but if you do, it will create a new one with a .LSY extension.
Also note that you can make minor edits to the LSX file and recompile it, perhaps to fix a minor bug in an older version of a program which has since undergone many changes that you don't want to introduce along with the bug fix. The only trick here is that the compiler expects every line of source code to be prefixed with the six digit location counter (see below) followed by two spaces, which you'll need to manually add to any lines you add. However, this is just a syntactic formality; the compiler does not care about the value of the location counters in the LSX file, so you can just set them all to a dummy value like 000000 or 999999.
Location Counters
The LSX file contains the location counter for each line of the source code, providing a way to located the source corresponding to BASIC errors. Traditionally programmers used line numbers for this purpose, but line numbers are cumbersome to deal with, cluttering up the source code, requiring renumbering utilities and management schemes to avoid duplicating line numbers in ++include modules, making the RUN modules larger and adding to the execution overhead. In modern A-Shell BASIC they have mostly been deprecated in favor of location counters, which require no additional overhead or effort, other than to keep a copy of the LSX files corresponding to the compiled programs for cross-reference purposes.
The standard BASIC error messages contain the location counter automatically, but if you are trapping errors yourself, you can retrieve the location counter using the ERR(8) function. You can also use the Dot Variables .LOCATION to retrieve the current location file, independent of error processing; see History notes below. Because it takes effort on the part of the user to write down and report error messages faithfully, and/or effort by the programmer to programmatically track them, you may want to take advantage of the built-in BASERR TRACE—by adding TRACE=BASERR to the miame.ini—which results in all BASIC errors, whether trapped or not, being logged to the ashlog.log file along with their location counters.
Note that by convention, location counter values are displayed in hex within internal error messages, log messages, LSX file, etc. But since the PRINT statement only outputs in decimal, you'll need to use a function such as MX_OCVT or the SOSLIB function Fn'Dec2Hex$() to convert the ERR(8) or .LOCATION values to hex, e.g. PRINT Fn'Dec2Hex$(ERR(8)).
Also note that because the LSX file only shows the location counter at the start of each source line, while an error might occur at a location in the middle of a source line, the location counter reported for an error may not necessarily match any location counter shown in the LSX file. For example, consider the following LSX excerpt:
003337 ELSEIF (dlg'ashdevinf_cntlsup_ary(x).gen'type = 5) THEN
00334f menucntl = dlg'ashdevinf_cntl_ary(x)
00335b IF (ABS(menucntl.clickcode) = ABS(click)) THEN
003369 fn'dlg'ashdevinf_clickcode2pointer = x
003371 EXIT
003375 ENDIF
003375
003375 ! comment bla bla bla
003375 ENDIF
003375 NEXT x
If the value of (x) in the second line generates a subscript out of range error (BASIC error 8), the location counter reported for the error will probably be somewhere between the location given for the start of the line (334f) and the location for the start of the next line (335b). So to locate the error, you'll just have to scroll through the LSX to find the pair of lines that bracket the error location.
The above example also illustrates the fact that many source lines do not increase the location counter at all, since they don't generate any executable code. The last 5 lines shown all have the same location counter, 3375.
Auto-Mapped Variables
If you don't use the /M switch, which reports un-mapped variables as errors, the compiler will automatically generate MAP statements for any such variables, and these will be listed near the bottom of the LSX file as follows:
MAP1 AUTO'MAPPED'VARS
MAP2 COMMON'RKEY,F,6
MAP2 COL'X,F,6
MAP2 COPIES,F,6
This explicit listing provides a relatively easy way for you to come in from the figurative cold—of living with the subtle errors introduced by inevitable typos—to take advantage of the compiler's ability to point out those typos to you before they become bugs. Just copy the AUTO'MAPPED'VARS MAP statements from the LSX file back to the original source and then you can compile with /M. That won't help resolve issues related to typos you've already introduced—although perhaps in seeing the AUTO'MAPPED'VARS all together, you might spot some suspicious ones—but it will allow you to benefit going forward.
Unreferenced Variables
When the /LF switch is used to create an LSX list file, unreferenced variables are listed at the end, as a convenience for those interested in clearing dead weight out of program. Note, however, that these are not errors, and in many cases, it isn't even desirable to remove them. For example, it is common to group misc variables under a heading, e.g.
MAP1 WORK'VARS
MAP2 X,F
etc.
Typically in the above case, there would probably be no explicit reference to WORK'VARS, but you couldn't just delete it without elevating the MAP2 variables beneath it to MAP1. So the new feature is only to be used a guide or ignored as you see fit.
Note: see Compiler Edit History, edits 452 and 500, for additional info on the List File option.
Procedure Reference Count
When compiling with /P or /PX, a section will be added to the bottom of the LSX file listing all the procedures and functions defined in the program, along with the reference count—i.e., the number of times the routine is called. For example:
Procedures, Functions [reference count]
======================================================
Fn'NextCh(ch) [2]
Fn'XMList'Load'Doc($xml,xmldoc$) [1]
Fn'XMList'Save'Doc($xml,xmldoc$,level,och) [0]
Fn'XMList'Get'Subtree'Callback($xml,item$,parent$,flags,$response) [1]
In the above example, we can see that there are several functions which are defined but are never used. These don't hurt anything, other than making the RUN modules larger than they need to be, so we might want to remove them. Fortunately, the /PX switch will do this for us automatically, showing a "<nc>" (for Never Called) next to any function that gets removed by this "tree-shaking" feature, e.g.
Procedures, Functions [reference count]
======================================================
Fn'NextCh(ch) [2]
Fn'Load'Doc($xml,xmldoc$) [1]
Fn'Save'Doc($xml,xmldoc$,level,och) [0] <nc>
Fn'Get'Subtree'Callback($xml,item$,parent$,flags,$response) [1] <nc>
Fn'Walk($xml,@fn'callback=.NULL,level=0 ,parent$=.null ) [0] <nc>
The above shows that the last three functions were removed from the RUN module, because they were never called. Note that this can occur even when the reference count is non-zero, as in the Fn'Get'Subtree'Callback example above, which was apparently referenced once, but still marked <nc>. This occurs when the only references to the target routine occur within other routines which themselves are never called. In the above case, it may be that the function Fn'Walk() references Fn'Get'Subtree'Callback(), but since Fn'Walk() is itself not referenced anywhere and thus never called, then by extension, Fn'Get'Subtree'Callback() is never called, and can thus be removed.
Note that routines that are removed by the /PX switch still show up in the LSX file, but the location counter will not increment. The routines removed this way are essentially treated by the compiler as if removed by conditional compilation logic.
Duplicate ++includes
You may find when perusing your LSX files that there are ++include files listed multiple times, because they are included from within multiple modules, but then conditionally compiled so as to not actually generate duplicate code. For example...
002339 ++include sosfunc:fnextch.bsi
! SOS63:FNEXTCH.BSI[907,10] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
002339 ! Function Name: Fn'NextCh(ch)
...
002339 ++ifndef INC_FNNEXTCH_
002339 define INC_FNNEXTCH_ = 1
002339
002339 Function Fn'NextCh(ch as b4:inputonly) as b4
002339
002339 if ch = 0 then ! [102]
002339 ch += 1
002339 endif
...
The above excerpt shows the ++include statement for the module sosfunc:fnextch.bsi, which contains a ++ifndef statement to prevent it from being compiled more than once if it is ++include'd multiple times. And we can see unchanging location counter (002339) that the compiler did not actually generate code for this instance of the module. The same phenomenon will occur if the routine is removed by the /PX switch because it is never called.
Note that while there is no real harm associated with these multiply-included but only singularly-compiled modules, they do take up space in the LSX file, and they do burn up a few extra CPU cycles as the compiler parses them, even if not actually "compiling" them. To avoid that, you may replace the ++include statements with ++include'once; or or add a ++PRAGMAs INCLUDE_GLOBAL_ONCE_ONLY, or use the /IGOO compiler switch, do automatically treat all ++include statements as if they were ++include'once).
Also See
The compiler /LSM switch which generates another kind of list file containing program metadata which is mostly used by APN, but which is somewhat related to the metadata contained in the LSX file.
History
2016 June, A-Shell 6.3.1514, Compiler edit 762: /PX switch added to the compiler.
2014 March, A-Shell 6.1.1382, Compiler edit 663: Function list with reference count added to LSX
2014 January, A-Shell 6.1.1373, Compiler edit 652: /P switch added to compiler
2007 June, A-Shell 5.0.990 , Compiler edit 356: /LF switch added to the compiler (LSX file introduced)
Note that the above feature introductions were subject to various subsequent fixes and enhancements; for details see the Compiler Edit History and search for "LSX."