Skip to content

Commit

Permalink
Implement local labels (1b, 2f) like in GNU assembler.
Browse files Browse the repository at this point in the history
  • Loading branch information
avm committed Dec 17, 2024
1 parent 11f9a9e commit 6182c2a
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/rars/ProgramStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ public void buildBasicStatementFromBasicInstruction(ErrorList errors) {
this.operands[this.numOperands++] = rounding_mode;
} else if (tokenType == TokenTypes.IDENTIFIER) {

int address = this.sourceProgram.getLocalSymbolTable().getAddressLocalOrGlobal(tokenValue);
int address = this.sourceProgram.getLocalSymbolTable().getAddressLocalOrGlobal(tokenValue, token.getSourceLine());
if (address == SymbolTable.NOT_FOUND) { // symbol used without being defined
errors.add(new ErrorMessage(this.sourceProgram, token.getSourceLine(), token.getStartPos(),
"Symbol \"" + tokenValue + "\" not found in symbol table."));
Expand Down
7 changes: 4 additions & 3 deletions src/rars/assembler/Assembler.java
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,8 @@ private boolean tokenListBeginsWithLabel(TokenList tokens) {
// 2-July-2010. DPS. Remove prohibition of operator names as labels
if (tokens.size() < 2)
return false;
return (tokens.get(0).getType() == TokenTypes.IDENTIFIER || tokens.get(0).getType() == TokenTypes.OPERATOR)
TokenTypes type0 = tokens.get(0).getType();
return (type0 == TokenTypes.IDENTIFIER || type0 == TokenTypes.OPERATOR || type0 == TokenTypes.INTEGER_5)
&& tokens.get(1).getType() == TokenTypes.COLON;
}

Expand Down Expand Up @@ -1002,7 +1003,7 @@ private void storeInteger(Token token, Directives directive, ErrorList errors) {
else if (token.getType() == TokenTypes.IDENTIFIER) {
if (this.inDataSegment) {
int value = fileCurrentlyBeingAssembled.getLocalSymbolTable()
.getAddressLocalOrGlobal(token.getValue());
.getAddressLocalOrGlobal(token.getValue(), token.getSourceLine());
if (value == SymbolTable.NOT_FOUND) {
// Record value 0 for now, then set up backpatch entry
int dataAddress = writeToDataSegment(0, lengthInBytes, token, errors);
Expand Down Expand Up @@ -1327,7 +1328,7 @@ private void resolve(SymbolTable localSymtab) {
DataSegmentForwardReference entry;
for (int i = 0; i < forwardReferenceList.size(); i++) {
entry = forwardReferenceList.get(i);
labelAddress = localSymtab.getAddressLocalOrGlobal(entry.token.getValue());
labelAddress = localSymtab.getAddressLocalOrGlobal(entry.token.getValue(), entry.token.getSourceLine());
if (labelAddress != SymbolTable.NOT_FOUND) {
// patch address has to be valid b/c we already stored there...
try {
Expand Down
9 changes: 8 additions & 1 deletion src/rars/assembler/Symbol.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public class Symbol {
private String name;
private int address;
private boolean data; // boolean true if data symbol false if text symbol.
private int sourceLine;

/**
* Basic constructor, creates a symbol object.
Expand All @@ -20,10 +21,11 @@ public class Symbol {
* @param data true if it represents data, false if code.
**/

public Symbol(String name, int address, boolean data) {
public Symbol(String name, int address, boolean data, int sourceLine) {
this.name = name;
this.address = address;
this.data = data;
this.sourceLine = sourceLine;
}

/**
Expand Down Expand Up @@ -57,6 +59,11 @@ public boolean getType() {
}


public int getSourceLine() {
return this.sourceLine;
}


/**
* Sets (replaces) the address of the the Symbol.
*
Expand Down
25 changes: 21 additions & 4 deletions src/rars/assembler/SymbolTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ public SymbolTable(String filename) {

public void addSymbol(Token token, int address, boolean b, ErrorList errors) {
String label = token.getValue();
if (getSymbol(label) != null) {
if (getSymbol(label) != null && !Character.isDigit(label.charAt(0))) {
errors.add(new ErrorMessage(token.getSourceProgram(), token.getSourceLine(), token.getStartPos(), "label \"" + label + "\" already defined"));
} else {
table.add(new Symbol(label, address, b));
table.add(new Symbol(label, address, b, token.getSourceLine()));
if (Globals.debug)
System.out.println("The symbol " + label + " with address " + address + " has been added to the " + this.filename + " symbol table.");
}
Expand Down Expand Up @@ -90,6 +90,23 @@ public int getAddress(String s) {
return NOT_FOUND;
}

public int getLocalAddress(String s, int sourceLine) {
if (s.length() == 2 && Character.isDigit(s.charAt(0))) {
String label = s.substring(0, 1);
var matching = table.stream()
.filter(sym -> sym.getName().equals(label))
.sorted((a, b) -> Integer.compare(a.getSourceLine(), b.getSourceLine()));
if (s.charAt(1) == 'f') {
return matching.filter(sym -> sym.getSourceLine() > sourceLine)
.findFirst().map(Symbol::getAddress).orElse(NOT_FOUND);
} else {
return matching.filter(sym -> sym.getSourceLine() <= sourceLine)
.reduce((first, last) -> last).map(Symbol::getAddress).orElse(NOT_FOUND);
}
}
return getAddress(s);
}

/**
* Method to return the address associated with the given label. Look first
* in this (local) symbol table then in symbol table of labels declared
Expand All @@ -98,8 +115,8 @@ public int getAddress(String s) {
* @param s The label.
* @return The memory address of the label given, or NOT_FOUND if not found in symbol table.
**/
public int getAddressLocalOrGlobal(String s) {
int address = this.getAddress(s);
public int getAddressLocalOrGlobal(String s, int sourceLine) {
int address = this.getLocalAddress(s, sourceLine);
return (address == NOT_FOUND) ? Globals.symbolTable.getAddress(s) : address;
}

Expand Down
9 changes: 7 additions & 2 deletions src/rars/assembler/TokenTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ public static TokenTypes matchTokenType(String value) {
// NO ACTION -- exception suppressed
}

// See if it is a local label reference like 1b or 2f
if (value.length() == 2 && Character.isDigit(value.charAt(0)) &&
(value.charAt(1) == 'f' || value.charAt(1) == 'b'))
return TokenTypes.IDENTIFIER;

// See if it is a real (fixed or floating point) number. Note that parseDouble()
// accepts integer values but if it were an integer literal we wouldn't get this far.
if (value.equals("Inf") || value.equals("NaN")) return TokenTypes.REAL_NUMBER;
Expand Down Expand Up @@ -179,7 +184,7 @@ public static TokenTypes matchTokenType(String value) {
return TokenTypes.OPERATOR;

// Test for identifier goes last because I have defined tokens for various
// MIPS constructs (such as operators and directives) that also could fit
// constructs (such as operators and directives) that also could fit
// the lexical specifications of an identifier, and those need to be
// recognized first.
if (isValidIdentifier(value))
Expand All @@ -190,7 +195,7 @@ public static TokenTypes matchTokenType(String value) {
}

/**
* Lets you know if given tokentype is for integers (INTGER_5, INTEGER_16, INTEGER_32).
* Lets you know if given tokentype is for integers (INTEGER_5, INTEGER_16, INTEGER_32).
*
* @param type the TokenType of interest
* @return true if type is an integer type, false otherwise.
Expand Down
21 changes: 21 additions & 0 deletions test/local-labels.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#exit:42
.globl main
.text
main:
# Tests simple looping behaviour
li t0, 60
li t1, 0
1:
addi t1, t1, 5
addi t0, t0, -1
bne t1, t0, 1b
bne t1, zero, 1f
2:
li a0, 0
li a7, 93
ecall

1:
li a0, 42
li a7, 93
ecall

0 comments on commit 6182c2a

Please sign in to comment.