From 0dd9cb5e496e3a0c0041513ba465e287e4b4024d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Pascual?= Date: Wed, 4 Feb 2026 17:20:30 +0100 Subject: [PATCH 1/2] Support label+integer as operand of instructions. --- src/rars/ProgramStatement.java | 9 +++++++++ src/rars/assembler/OperandFormat.java | 13 ++++++++++++- test/label_plus1.s | 20 ++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 test/label_plus1.s diff --git a/src/rars/ProgramStatement.java b/src/rars/ProgramStatement.java index 676df16a6..20a0090ca 100644 --- a/src/rars/ProgramStatement.java +++ b/src/rars/ProgramStatement.java @@ -239,6 +239,15 @@ public void buildBasicStatementFromBasicInstruction(ErrorList errors) { } boolean absoluteAddress = true; // (used below) + if (i + 2 < strippedTokenList.size()) { // support label+integer + Token op = strippedTokenList.get(i + 1); + Token offset = strippedTokenList.get(i + 2); + if (op.getType() == TokenTypes.PLUS && TokenTypes.isIntegerTokenType(offset.getType())) { + address = address + Integer.parseInt(offset.getValue()); + i = i + 2; + } + } + if (instruction instanceof BasicInstruction) { BasicInstructionFormat format = ((BasicInstruction) instruction).getInstructionFormat(); if (format == BasicInstructionFormat.B_FORMAT) { diff --git a/src/rars/assembler/OperandFormat.java b/src/rars/assembler/OperandFormat.java index ad2c5e7cf..c22131394 100644 --- a/src/rars/assembler/OperandFormat.java +++ b/src/rars/assembler/OperandFormat.java @@ -51,11 +51,22 @@ static Instruction bestOperandMatch(TokenList tokenList, ArrayList private static boolean numOperandsCheck(TokenList cand, Instruction spec, ErrorList errors) { int numOperands = cand.size() - 1; int reqNumOperands = spec.getTokenList().size() - 1; + int i = 1; + while (i < cand.size()) { // support labal+integer, count these 3 tokens as 1 + if (cand.get(i).getType() == TokenTypes.IDENTIFIER && i + 2 < cand.size()) { + Token op = cand.get(i + 1); + Token offset = cand.get(i + 2); + if (op.getType() == TokenTypes.PLUS && TokenTypes.isIntegerTokenType(offset.getType())) { + numOperands = numOperands - (3 - 1); + i = i + 2; // skip the next two tokens + } + } + i = i + 1; + } Token operator = cand.get(0); if (numOperands == reqNumOperands) { return true; } else if (numOperands < reqNumOperands) { - String mess = "Too few or incorrectly formatted operands. Expected: " + spec.getExampleFormat(); generateMessage(operator, mess, errors); } else { diff --git a/test/label_plus1.s b/test/label_plus1.s new file mode 100644 index 000000000..388a348fe --- /dev/null +++ b/test/label_plus1.s @@ -0,0 +1,20 @@ +#stdout:cdef +#exit:42 +.data +data: +.string "abcdef" +ptr: +.word data +.word 2+3+4 + +.text +#li a3, 4+4 + +li a7, 4 # PrintString +la a0, data+2 +ecall + +ok: +li a7, 93 # Exit2 +li a0, 42 +ecall From 1c2619555b7f330473999b4c7607c27eacc7f5d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Pascual?= Date: Wed, 4 Feb 2026 20:06:49 +0100 Subject: [PATCH 2/2] Support label+integer in data directives. --- src/rars/assembler/Assembler.java | 38 ++++++++++++++++++++++--------- test/label_plus1.s | 24 +++++++++---------- test/label_plus2.s | 31 +++++++++++++++++++++++++ test/label_plus3.s | 35 ++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 23 deletions(-) create mode 100644 test/label_plus2.s create mode 100644 test/label_plus3.s diff --git a/src/rars/assembler/Assembler.java b/src/rars/assembler/Assembler.java index fa5ba0e37..bbc624698 100644 --- a/src/rars/assembler/Assembler.java +++ b/src/rars/assembler/Assembler.java @@ -916,7 +916,7 @@ private void storeNumeric(TokenList tokens, Directives directive, ErrorList erro } for (int i = 0; i < repetitions; i++) { if (Directives.isIntegerDirective(directive)) { - storeInteger(valueToken, directive, errors); + storeInteger(valueToken, directive, 0, errors); } else { storeRealNumber(valueToken, directive, errors); } @@ -928,10 +928,24 @@ private void storeNumeric(TokenList tokens, Directives directive, ErrorList erro // if not in ".word w : n" format, must just be list of one or more values. for (int i = tokenStart; i < tokens.size(); i++) { token = tokens.get(i); + int offset = 0; + while (i + 2 < tokens.size() // support for label+integer + && tokens.get(i+1).getType() == TokenTypes.PLUS) { + Token offsetToken = tokens.get(i+2); + if (TokenTypes.isIntegerTokenType(offsetToken.getType())) { + offset = offset + Integer.parseInt(offsetToken.getValue()); + } else { + errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, offsetToken.getSourceLine(), offsetToken.getStartPos(), "Only integers can be used as offsets")); + } + i = i + 2; + } if (Directives.isIntegerDirective(directive)) { - storeInteger(token, directive, errors); + storeInteger(token, directive, offset, errors); } if (Directives.isFloatingDirective(directive)) { + if (offset != 0) { + errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, token.getSourceLine(), token.getStartPos(), "Offsets are not supported for floating point values")); + } storeRealNumber(token, directive, errors); } } @@ -942,13 +956,13 @@ private void storeNumeric(TokenList tokens, Directives directive, ErrorList erro // Called by storeNumeric() // NOTE: The token itself may be a label, in which case the correct action is // to store the address of that label (into however many bytes specified). - private void storeInteger(Token token, Directives directive, ErrorList errors) { + private void storeInteger(Token token, Directives directive, int offset, ErrorList errors) { int lengthInBytes = DataTypes.getLengthInBytes(directive); if (TokenTypes.isIntegerTokenType(token.getType())) { int value; long longvalue; if (TokenTypes.INTEGER_64 == token.getType()) { - longvalue = Binary.stringToLong(token.getValue()); + longvalue = Binary.stringToLong(token.getValue()) + offset; value = (int)longvalue; if (directive != Directives.DWORD){ errors.add(new ErrorMessage(ErrorMessage.WARNING, token.getSourceProgram(), token.getSourceLine(), @@ -956,7 +970,7 @@ private void storeInteger(Token token, Directives directive, ErrorList errors) { + " is out-of-range and truncated to " + Binary.intToHexString(value))); } }else{ - value = Binary.stringToInt(token.getValue()); + value = Binary.stringToInt(token.getValue()) + offset; longvalue = value; } @@ -1019,9 +1033,9 @@ else if (token.getType() == TokenTypes.IDENTIFIER) { if (value == SymbolTable.NOT_FOUND) { // Record value 0 for now, then set up backpatch entry int dataAddress = writeToDataSegment(0, lengthInBytes, token, errors); - currentFileDataSegmentForwardReferences.add(dataAddress, lengthInBytes, token); + currentFileDataSegmentForwardReferences.add(dataAddress, lengthInBytes, token, offset); } else { // label already defined, so write its address - writeToDataSegment(value, lengthInBytes, token, errors); + writeToDataSegment(value + offset, lengthInBytes, token, errors); } } // Data segment check done previously, so this "else" will not be. // See 11/20/06 note above. @@ -1312,8 +1326,8 @@ private int size() { // - memory address to receive the label's address once resolved // - number of address bytes to store (1 for .byte, 2 for .half, 4 for .word) // - the label's token. All its information will be needed if error message generated. - private void add(int patchAddress, int length, Token token) { - forwardReferenceList.add(new DataSegmentForwardReference(patchAddress, length, token)); + private void add(int patchAddress, int length, Token token, int offset) { + forwardReferenceList.add(new DataSegmentForwardReference(patchAddress, length, token, offset)); } // Add the entries of another DataSegmentForwardReferences object to this one. @@ -1344,7 +1358,7 @@ private void resolve(SymbolTable localSymtab) { if (labelAddress != SymbolTable.NOT_FOUND) { // patch address has to be valid b/c we already stored there... try { - Globals.memory.set(entry.patchAddress, labelAddress, entry.length); + Globals.memory.set(entry.patchAddress, labelAddress + entry.offset, entry.length); } catch (AddressErrorException aee) { } forwardReferenceList.remove(i); @@ -1368,11 +1382,13 @@ private class DataSegmentForwardReference { int patchAddress; int length; Token token; + int offset; - DataSegmentForwardReference(int patchAddress, int length, Token token) { + DataSegmentForwardReference(int patchAddress, int length, Token token, int offset) { this.patchAddress = patchAddress; this.length = length; this.token = token; + this.offset = offset; } } diff --git a/test/label_plus1.s b/test/label_plus1.s index 388a348fe..49b5294e6 100644 --- a/test/label_plus1.s +++ b/test/label_plus1.s @@ -1,20 +1,20 @@ #stdout:cdef #exit:42 -.data + .data data: -.string "abcdef" + .string "abcdef" ptr: -.word data -.word 2+3+4 + .word data + .word 2+3+4 -.text -#li a3, 4+4 + .text + #li a3, 4+4 -li a7, 4 # PrintString -la a0, data+2 -ecall + li a7, 4 # PrintString + la a0, data+2 + ecall ok: -li a7, 93 # Exit2 -li a0, 42 -ecall + li a7, 93 # Exit2 + li a0, 42 + ecall diff --git a/test/label_plus2.s b/test/label_plus2.s new file mode 100644 index 000000000..0c0391911 --- /dev/null +++ b/test/label_plus2.s @@ -0,0 +1,31 @@ +#stdout:cdef +#exit:42 + .data +data: + .string "abcdef" +ptr: + .word data+3 + # .word 2+3+4 # This is not supported because of limitations of the tokenizer. Since commas are optional and unary minus and plus are supported, "3" "+" "3" is ambigous with "3" "+3" + + .text + + li a7, 4 # PrintString + la a0, data+2 + ecall + + lw t0, ptr + la a0, data+3 + bne t0, a0, fail + lb t1, 0(t0) + li t2, 'd' + beq t1, t2, ok + +fail: + li a7, 93 # Exit2 + li a0, 1 + ecall + +ok: + li a7, 93 # Exit2 + li a0, 42 + ecall diff --git a/test/label_plus3.s b/test/label_plus3.s new file mode 100644 index 000000000..a2dd7f4c8 --- /dev/null +++ b/test/label_plus3.s @@ -0,0 +1,35 @@ +#stdout:fghi +#exit:42 +.data +ptr_fwd: + .word data+5 +data: + .string "abcdefghi" +ptr: + .word data+3 + +.text + + li a7, 4 # PrintString + lw a0, ptr_fwd + ecall + + lw t0, ptr + la a0, data+3 + bne t0, a0, fail + lw t0, ptr_fwd + la a0, data+5 + bne t0, a0, fail + lb t1, 0(t0) + li t2, 'f' + beq t1, t2, ok + +fail: + li a7, 93 # Exit2 + li a0, 1 + ecall + +ok: + li a7, 93 # Exit2 + li a0, 42 + ecall