Finish logged machine

This commit is contained in:
Jan-Niclas Loosen
2025-10-25 18:44:02 +02:00
parent 59b6371966
commit a22a2f3ea6
6 changed files with 102 additions and 83 deletions

View File

@@ -1,6 +1,4 @@
package de.unitrier.st.uap.w25.tram; package de.unitrier.st.uap.w25.tram;
import java.nio.file.attribute.UserPrincipalLookupService;
import java.util.*; import java.util.*;
public class AbstractMachine { public class AbstractMachine {
@@ -12,11 +10,13 @@ public class AbstractMachine {
protected int PC = 0; protected int PC = 0;
protected int TOP = -1; protected int TOP = -1;
// Init machine with program and empty stack
public AbstractMachine(Instruction[] prog) { public AbstractMachine(Instruction[] prog) {
this.prog = new ArrayList<>(Arrays.asList(prog)); this.prog = new ArrayList<>(Arrays.asList(prog));
this.stack = new ArrayList<>(); this.stack = new ArrayList<>();
} }
// Init machine with program and stack
public AbstractMachine(Instruction[] prog, Integer[] stack) { public AbstractMachine(Instruction[] prog, Integer[] stack) {
this(prog); this(prog);
@@ -25,25 +25,15 @@ public class AbstractMachine {
} }
// Executes until halts and returns final configuration // Executes until halts and returns final configuration
public String execute() { public void execute() {
while(!isHalted()) { while(!isHalted()) {
executeStep(); executeStep();
} }
return configuration(); confStr();
}
// Executes until halts and returns configurations of all steps
public ArrayList<String> executeDebug() {
ArrayList<String> out = new ArrayList<>();
while(!isHalted()) {
String conf = executeStep();
out.add(conf);
}
return out;
} }
// Executes single step and returns configuration // Executes single step and returns configuration
public String executeStep() { public void executeStep() {
ensureCapacity(this.TOP); ensureCapacity(this.TOP);
Instruction inst = this.prog.get(this.PC); Instruction inst = this.prog.get(this.PC);
@@ -191,8 +181,6 @@ public class AbstractMachine {
break; break;
default: break; default: break;
} }
return configuration();
} }
public boolean isHalted() { public boolean isHalted() {
@@ -233,23 +221,30 @@ public class AbstractMachine {
} }
} }
// Prints the machine's current configuration // Returns the machine's current configuration as string
public String configuration() { public String confStr() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("TOP=").append(this.TOP) sb.append("TOP=").append(this.TOP)
.append(" PC=").append(this.PC) .append(" PC=").append(this.PC)
.append(" PP=").append(this.PP) .append(" PP=").append(this.PP)
.append(" FP=").append(this.FP) .append(" FP=").append(this.FP)
.append("\nSTACK: ["); .append("\nSTACK: ")
.append(stackStr());
return sb.toString();
}
// Returns the machine's current stack as string
public String stackStr() {
StringBuilder sb = new StringBuilder();
sb.append("[");
int limit = Math.min(this.stack.size(), this.TOP + 1); int limit = Math.min(this.stack.size(), this.TOP + 1);
for (int i = 0; i < limit; i++) { for (int i = 0; i < limit; i++) {
sb.append(this.stack.get(i)); sb.append(this.stack.get(i));
if (i < limit - 1) sb.append(", "); if (i < limit - 1) sb.append(", ");
} }
sb.append("]"); sb.append("]");
return sb.toString(); return sb.toString();
} }

View File

@@ -4,7 +4,6 @@ import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
public class AbstractMachineTests { public class AbstractMachineTests {
@Test @Test
void testExample1() { void testExample1() {
Instruction[] code = Assembler.readTRAMCode("tramcode/example1.tram"); Instruction[] code = Assembler.readTRAMCode("tramcode/example1.tram");
@@ -25,7 +24,7 @@ public class AbstractMachineTests {
assertTrue(tram.isHalted(), "Machine should halt."); assertTrue(tram.isHalted(), "Machine should halt.");
var results = tram.results(); var results = tram.results();
assertEquals(200, results.get(results.size() - 2), "Expected value 200 since x!=0."); assertEquals(200, results.get(results.size() - 2), "Expected value 200 since x!=0.");
assertEquals(3, results.get(results.size() - 1), "Expected final constant 3 on stack."); assertEquals(3, results.getLast(), "Expected final constant 3 on stack.");
} }
@Test @Test

View File

@@ -1,7 +1,3 @@
/**
* Instructions for TRAM 2025
*/
package de.unitrier.st.uap.w25.tram; package de.unitrier.st.uap.w25.tram;
public class Instruction public class Instruction

View File

@@ -2,42 +2,60 @@ package de.unitrier.st.uap.w25.tram;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
// Write subclass to enhance Single-Responsibility-Principle
public class LoggedMachine extends AbstractMachine { public class LoggedMachine extends AbstractMachine {
private static final Logger logger = LogManager.getLogger(LoggedMachine.class); protected static Logger logger = LogManager.getLogger(LoggedMachine.class);
protected int stepCounter = 0;
// No changes in the constructor
public LoggedMachine(Instruction[] prog) { public LoggedMachine(Instruction[] prog) {
super(prog); super(prog);
} }
// No changes in the constructor
public LoggedMachine(Instruction[] prog, Integer[] stack) { public LoggedMachine(Instruction[] prog, Integer[] stack) {
super(prog, stack); super(prog, stack);
} }
@Override // Enable file logging
public String executeStep() { public static void toFile(String fileName) {
String confBefore = configuration(); ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
logger.debug("Before step:\n" + confBefore);
String confAfter = super.executeStep(); AppenderComponentBuilder fileAppender = builder.newAppender("File", "File")
logger.debug("After step:\n" + confAfter); .addAttribute("fileName", fileName)
.add(builder.newLayout("PatternLayout")
.addAttribute("pattern", "%d{HH:mm:ss} %-5level %msg%n"));
return confAfter; builder.add(fileAppender);
builder.add(builder.newRootLogger(Level.DEBUG).add(builder.newAppenderRef("File")));
LoggerContext ctx = LoggerContext.getContext(false);
ctx.start(builder.build());
logger = LogManager.getLogger(LoggedMachine.class);
} }
@Override @Override
public String execute() { public void execute() {
logger.info("Execution started"); logger.info("Executing...");
String result = super.execute(); logger.debug("{}: {}", 0, confStr());
logger.info("Execution finished:\n" + configuration()); while(!isHalted()) {
return result; executeStep();
}
logger.info("Finished with STACK: {}", stackStr());
} }
@Override @Override
public java.util.ArrayList<String> executeDebug() { public void executeStep() {
logger.info("Debug execution started"); int step = stepCounter++;
var out = super.executeDebug(); super.executeStep();
logger.info("Debug execution finished"); logger.debug("{}: {}", step, confStr());
return out;
} }
} }

View File

@@ -1,40 +1,33 @@
package de.unitrier.st.uap.w25.tram; package de.unitrier.st.uap.w25.tram;
final class Main import org.apache.logging.log4j.Level;
{ import org.apache.logging.log4j.core.config.Configurator;
private Main(){}
static void main(String[] argv) {
Instruction[] code = Assembler.readTRAMCode(
// "tramcode/square.tram"
// "tramcode/wrapper.tram"
// "tramcode/example1.tram"
// "tramcode/example2.tram"
//"tramcode/example3.tram"
"tramcode/test.tram"
);
int lineNr=0; final class Main {
for(Instruction instr: code) { private Main() {}
if (instr != null) {
System.out.println(String.format("%03d", lineNr) + "| " + instr.toString());
lineNr++;
}
}
// TODO: Create an instance of the abstract machine with reasonable parameters static void main(String[] argv) {
AbstractMachine tram = new AbstractMachine(code, new Integer[]{}); // empty stack or predefined args // Configurator.setRootLevel(Level.DEBUG);
Configurator.setRootLevel(Level.INFO);
System.out.println("Initial configuration:"); Instruction[] code = Assembler.readTRAMCode(
System.out.println(tram.configuration()); //"tramcode/square.tram"
//"tramcode/wrapper.tram"
//"tramcode/example1.tram"
//"tramcode/example2.tram"
//"tramcode/example3.tram"
"tramcode/test.tram"
);
// Stepwise execution (debug) // int lineNr = 0;
System.out.println("\nExecution trace:"); // for (Instruction instr : code) {
for (String conf : tram.executeDebug()) { // if (instr != null) {
System.out.println(conf); // System.out.println(String.format("%03d", lineNr) + "| " + instr);
} // lineNr++;
// }
// }
System.out.println("\nFinal configuration:"); LoggedMachine tram = new LoggedMachine(code, new Integer[]{}); // empty stack or predefined args
System.out.println(tram.configuration()); tram.execute();
} }
} }

View File

@@ -10,8 +10,8 @@
<orderEntry type="module-library"> <orderEntry type="module-library">
<library name="JUnit4"> <library name="JUnit4">
<CLASSES> <CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/junit/junit/4.13.1/junit-4.13.1.jar!/" /> <root url="jar://$MODULE_DIR$/lib/junit-4.13.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar!/" /> <root url="jar://$MODULE_DIR$/lib/hamcrest-core-1.3.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />
@@ -33,5 +33,23 @@
<SOURCES /> <SOURCES />
</library> </library>
</orderEntry> </orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/log4j-core-2.24.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/log4j-api-2.24.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
</component> </component>
</module> </module>