fix(as370): a duplication factor may be a parenthesised expression (#93) - #95
Merged
Merged
Conversation
Assembler XF takes an absolute expression in parentheses wherever a decimal
self-defining term may stand as a DC/DS duplication factor. xdcds.asm:103 scans
it: a digit takes the self-defining path, anything else falls to DUPF, which
tests for a left parenthesis and evaluates what follows as an expression --
DUPF CLI CHAR1,JLPARN SEE IF EXPRESSION
BNE TYPE OMITTED FIELD
ST R5,ADUPFAC SAVE ADDRESS OF EXPRESSION
-- so the character is the constant's TYPE only when it is neither a digit nor
'('. as370 had no DUPF arm and went straight to the type test, so every such
operand came out ERR198 "invalid type" and reserved nothing, moving every symbol
after it in the section.
The scan is balanced rather than strchr(')'): the common shape carries an inner
parenthesis, ((A-B)/8), where the first ')' is in the wrong place. A test pins
that on its own, because a truncated expression still yields a number and would
size the constant wrongly in silence.
expr_val could not be used as it stands. Its leading-'(' guard reads a
parenthesis as a subscript -- right for a machine operand like (R1), wrong for an
expression that merely begins with one, which it valued at 0. expr_val_full is
the same evaluator without that guard.
Measured on the guest rather than assumed (JOB02900, listing committed as
tests/listref/ifox-listing-dupfac.txt):
(0)X'00' legal and SILENT -- reserves nothing, no diagnostic
forward ref IFO231 + IFO217 + IFO206, reserves nothing
negative IFO206, reserves nothing
The forward-reference rule is what makes the construct implementable in two
passes. By pass 2 the symbol is defined, so re-deriving the verdict there would
allocate where pass 1 allocated nothing and the location counter would move
between the passes -- every symbol after it shifting silently. Because IFOX
rejects it outright, pass 1's verdict is recorded and pass 2 looks it up.
IFO217 is severity 12 (jermsgcd.asm SEV217) where IFO231 and IFO206 are 8, so one
forward reference takes the assembly to RC 12. That is the oracle's return code
and it is reproduced rather than flattened to 8.
Every location counter, the section length and the flagged-statement count now
match the oracle line for line: 5/4/5/0/4 bytes, length 0x3A, RC 12, two
statements flagged over four messages.
No deck oracle: IFOX00 does not punch at severity 12. The listing carries the LOC
and OBJECT CODE columns, which is what a duplication factor decides, and run.sh
asserts the section length and both TXT cards against them.
The ecosystem is untouched -- 826 modules unchanged, no corpus module moved. On a
local tree of real IBM MVS assembler, 20 of a 277-module sample now assemble
clean that did not before (36% -> 43%), none lost.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #93.
Assembler XF takes an absolute expression in parentheses wherever a decimal self-defining term may stand as a DC/DS duplication factor.
xdcds.asm:103scans it — a digit takes the self-defining path, anything else falls toDUPF:The character is the constant's type only when it is neither a digit nor
(. as370 had noDUPFarm and went straight to the type test, so every such operand came outERR198 invalid typeand reserved nothing — moving every symbol after it in the section.Measured, not assumed
tests/oracle/capture.pyon mvsdev, JOB02900, listing committed astests/listref/ifox-listing-dupfac.txt. Seven cases, and three decided the design:((AREAEND-AREASTA)/8)X'00'backward(4)X'00'((AREAEND-AREASTA)/8)XasDS(0)X'00'4X'00'controlIFO231+IFO217+IFO206, reserves nothingIFO206, reserves nothingRC 12, two statements flagged over four messages.
The forward-reference rule is what makes this implementable
By pass 2 the forward symbol is defined. Re-deriving the verdict there would allocate where pass 1 allocated nothing, the location counter would move between the passes, and every symbol after it would shift — silently. Because IFOX rejects it outright (
SYMBOL NOT PREVIOUSLY DEFINED, and the statement reserves nothing), pass 1's verdict can simply be recorded, and pass 2 looks it up instead of re-evaluating.That is the whole reason the fixture asks the guest about a forward reference at all.
Two traps in the implementation
The scan must be balanced, not
strchr(')'). The common shape carries an inner parenthesis,((A-B)/8), where the first)is in the wrong place. A truncated expression still yields a number, so this would size the constant wrongly in silence —dupfac_nestedpins it on its own. (The neighbouringL(expr)length modifier still has thestrchrshape; adjacent, and not this change.)expr_valcould not be used as it stands. Its leading-(guard reads a parenthesis as a subscript — right for a machine operand like(R1), wrong for an expression that merely begins with one, which it valued at 0.expr_val_fullis the same evaluator without that guard. This cost a debugging round: withexpr_val, the backward-reference case silently reserved nothing and the negative case silently became legal.Severity
IFO217is severity 12 (jermsgcd.asmSEV217) whereIFO231andIFO206are 8, so one forward reference takes the whole assembly to RC 12. Reproduced rather than flattened to 8 — matching the oracle's return code is the reason these diagnostics exist.Verification
0x3A, both TXT cards, RC 12, 2 statements flagged over 4 messagestests/corpus/check.shno module moved— 743 decks byte-identicaltests/run.shALL SAMPLES BYTE-IDENTICAL TO IFOX00tests/listref/check.shBoth new cases fail against
main(expected RC 12, got 8/expected RC 0, got 8).On a local tree of real IBM MVS assembler — not committed here — 20 of a 277-module spread sample now assemble clean that did not before (36% → 43%), none lost. Among them
IFNX6C.ASM, which is IFOX00's own source.Built warning-clean with real gcc 14.2
-Werroron mvsdev as well as clang; it caught a-Wmisleading-indentationthat clang accepts.No deck oracle: IFOX00 does not punch at severity 12, so
capture.pyreturned the listing alone. Sufficient here — the LOC and OBJECT CODE columns are exactly what a duplication factor decides.