diff --git a/.idea/misc.xml b/.idea/misc.xml
index 56c0bcd..495fdee 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,3 +1,4 @@
+
@@ -6,7 +7,7 @@
-
+
\ No newline at end of file
diff --git a/prg/Makefile b/prg/Makefile
index 0ac3283..733e3a0 100644
--- a/prg/Makefile
+++ b/prg/Makefile
@@ -1,6 +1,7 @@
JAVA = java --enable-preview
+PHASE =
.PHONY : %
% : %.pins25
- $(JAVA) -classpath ../bin pins25.phase.SynAn $<
+ $(JAVA) -classpath ../bin pins25.phase.$(PHASE) $<
diff --git a/src/pins25/common/Mem.java b/src/pins25/common/Mem.java
new file mode 100644
index 0000000..50ced73
--- /dev/null
+++ b/src/pins25/common/Mem.java
@@ -0,0 +1,153 @@
+package pins25.common;
+
+import java.util.*;
+
+/**
+ * Klicni zapisi in dostopi do spremenljivk.
+ *
+ * Vse spremenljivke (in parametri, ki so samo posebna vrsta spremenljivke)
+ * katerih ime se zacne z {@code debug}, so lahko nastavljene na {@code null}.
+ * Uporabljajo se samo za izpis sledenja delovanja abstraktnega skladovne
+ * stroja.
+ */
+public class Mem {
+
+ @SuppressWarnings({ "doclint:missing" })
+ private Mem() {
+ throw new Report.InternalError();
+ }
+
+ // --- KLICNI ZAPISI ---
+
+ /**
+ * Klicni zapis.
+ */
+ public static class Frame {
+
+ /** Ime oznake, torej polno ime funkcije. */
+ public final String name;
+
+ /** Staticna globina funkcije. */
+ public final Integer depth;
+
+ /** Skupna velikost parametrov (skupaj s staticno povezavo). */
+ public final Integer parsSize;
+
+ /**
+ * Skupna velikost lokalnih spremenljivk (skupaj s shranjenim klicnim kazalcem
+ * in povratnim naslovom.
+ */
+ public final Integer varsSize;
+
+ /** Dostopi do parametrov. */
+ public final List debugPars;
+
+ /** Dostopi do lokalnih spremenljivk. */
+ public final List debugVars;
+
+ /**
+ * Ustvari nov klicni zapis.
+ *
+ * @param name Ime oznake, torej polno ime funkcije.
+ * @param depth Staticna globina funkcije.
+ * @param parsSize Skupna velikost parametrov (skupaj s staticno povezavo).
+ * @param varsSize Skupna velikost lokalnih spremenljivk (skupaj s shranjenim
+ * klicnim kazalcem in povratnim naslovom.
+ * @param debugPars Dostopi do parametrov.
+ * @param debugVars Dostopi do lokalnih spremenljivk.
+ */
+ public Frame(final String name, final Integer depth, final Integer parsSize, final Integer varsSize,
+ List debugPars, final List debugVars) {
+ this.name = name;
+ this.depth = depth;
+ this.parsSize = parsSize;
+ this.varsSize = varsSize;
+ this.debugPars = Collections.unmodifiableList(debugPars);
+ this.debugVars = Collections.unmodifiableList(debugVars);
+ }
+
+ }
+
+ // --- DOSTOPI DO SPREMENLJIVK ---
+
+ /**
+ * Dostop do spremenljivke.
+ */
+ public static abstract class Access {
+
+ /** Velikost spremenljivke. */
+ public final Integer size;
+
+ /** Zacetna vrednost spremenljivke. */
+ public final List inits;
+
+ /**
+ * Ustvari nov dostop do spremenljivke.
+ *
+ * @param size Velikost spremenljivke.
+ * @param inits Zacetna vrednost spremenljivke.
+ */
+ public Access(final Integer size, final Vector inits) {
+ this.size = size;
+ this.inits = inits == null ? null : Collections.unmodifiableList(new Vector(inits));
+ }
+
+ }
+
+ /**
+ * Absolutni dostop do spremenljivke (na staticen naslov).
+ */
+ public static class AbsAccess extends Access {
+
+ /** Ime oznake (ime spremenljivke). */
+ public final String name;
+
+ /**
+ * Ustvari nov absolutni dostop do spremenljivke.
+ *
+ * @param name Ime oznake (ime spremenljivke).
+ * @param size Velikost spremenljivke.
+ * @param inits Zacetna vrednost spremenljivke.
+ */
+ public AbsAccess(final String name, final Integer size, final Vector inits) {
+ super(size, inits);
+ this.name = name;
+ }
+
+ }
+
+ /**
+ * Relativni dostop do spremenljivke (na skladu).
+ */
+ public static class RelAccess extends Access {
+
+ /** Odmik od vrha klicnega zapisa, torej od vrednosti klicnega kazalca. */
+ public final Integer offset;
+
+ /** Staticna globina spremenljivke. */
+ public final Integer depth;
+
+ /** Ime spremenljivke. */
+ public final String debugName;
+
+ /**
+ * Ustvari nov relativni dostop do spremenljivke.
+ *
+ * @param offset Odmik od vrha klicnega zapisa, torej od vrednosti klicnega
+ * kazalca.
+ * @param depth Staticna globina spremenljivke.
+ * @param size Velikost spremenljivke.
+ * @param inits Zacetna vrednost spremenljivke.
+ * @param debugName Ime spremenljivke.
+ */
+ public RelAccess(final Integer offset, final Integer depth, Integer size, final Vector inits,
+ final String debugName) {
+ super(size, inits);
+ this.offset = offset;
+ this.depth = depth;
+ this.debugName = debugName;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/pins25/common/Token.java b/src/pins25/common/Token.java
index 86d06cb..2685303 100644
--- a/src/pins25/common/Token.java
+++ b/src/pins25/common/Token.java
@@ -149,46 +149,6 @@ public record Token(Report.Location location, Symbol symbol, String lexeme) impl
* Simbol {@code )}.
*/
RPAREN;
-
- @Override
- public String toString() {
- return switch (this) {
- case INTCONST -> "integer constant";
- case CHARCONST -> "character constant";
- case STRINGCONST -> "string constant";
- case IDENTIFIER -> "identifier";
- case FUN -> "'fun'";
- case VAR -> "'var'";
- case IF -> "'if'";
- case THEN -> "'then'";
- case ELSE -> "'else'";
- case WHILE -> "'while'";
- case DO -> "'do'";
- case LET -> "'let'";
- case IN -> "'in'";
- case END -> "'end'";
- case ASSIGN -> "'='";
- case COMMA -> "','";
- case AND -> "'&&'";
- case OR -> "'||'";
- case NOT -> "'!'";
- case EQU -> "'=='";
- case NEQ -> "'!='";
- case GTH -> "'>'";
- case LTH -> "'<'";
- case GEQ -> "'>='";
- case LEQ -> "'<='";
- case ADD -> "'+'";
- case SUB -> "'-'";
- case MUL -> "'*'";
- case DIV -> "'/'";
- case MOD -> "'%'";
- case PTR -> "'^'";
- case LPAREN -> "'('";
- case RPAREN -> "')'";
- default -> this.toString();
- };
- }
}
@Override
diff --git a/src/pins25/phase/LexAn.java b/src/pins25/phase/LexAn.java
index adcc575..888f692 100644
--- a/src/pins25/phase/LexAn.java
+++ b/src/pins25/phase/LexAn.java
@@ -409,8 +409,8 @@ public class LexAn implements AutoCloseable {
nextChar();
if (buffChar == 'n' || buffChar == '\\' || buffChar == '"') {
} else if (isHex()) {
- nextChar();
lexeme.append((char) buffChar);
+ nextChar();
if (!isHex()) {
throw new Report.Error(currentLocation(), "Invalid ascii code '" + (char) buffChar + "'.");
}
diff --git a/src/pins25/phase/Memory.java b/src/pins25/phase/Memory.java
new file mode 100644
index 0000000..a2d4dc3
--- /dev/null
+++ b/src/pins25/phase/Memory.java
@@ -0,0 +1,422 @@
+package pins25.phase;
+
+import java.util.*;
+
+import pins25.common.*;
+
+/**
+ * Izracun pomnilniske predstavitve.
+ */
+public class Memory {
+
+ @SuppressWarnings({"doclint:missing"})
+ public Memory() {
+ throw new Report.InternalError();
+ }
+
+ /**
+ * Abstraktno sintaksno drevo z dodanimi atributi izracuna pomnilniske
+ * predstavitve.
+ *
+ * Atributi:
+ *
+ * - ({@link Abstr}) lokacija kode, ki pripada posameznemu vozliscu;
+ * - ({@link SemAn}) definicija uporabljenega imena;
+ * - ({@link SemAn}) ali je dani izraz levi izraz;
+ * - ({@link Memory}) klicni zapis funkcije;
+ * - ({@link Memory}) dostop do parametra;
+ * - ({@link Memory}) dostop do spremenljivke.
+ *
+ */
+ public static class AttrAST extends SemAn.AttrAST {
+
+ /**
+ * Atribut: klicni zapis funkcije.
+ */
+ public final Map attrFrame;
+
+ /**
+ * Atribut: dostop do parametra.
+ */
+ public final Map attrParAccess;
+
+ /**
+ * Atribut: dostop do spremenljivke.
+ */
+ public final Map attrVarAccess;
+
+ /**
+ * Ustvari novo abstraktno sintaksno drevo z dodanimi atributi izracuna
+ * pomnilniske predstavitve.
+ *
+ * @param attrAST Abstraktno sintaksno drevo z dodanimi atributi
+ * semanticne analize.
+ * @param attrFrame Attribut: klicni zapis funkcije.
+ * @param attrParAccess Attribut: dostop do parametra.
+ * @param attrVarAccess Attribut: dostop do spremenljivke.
+ */
+ public AttrAST(final SemAn.AttrAST attrAST, final Map attrFrame,
+ final Map attrParAccess, final Map attrVarAccess) {
+ super(attrAST);
+ this.attrFrame = attrFrame;
+ this.attrParAccess = attrParAccess;
+ this.attrVarAccess = attrVarAccess;
+ }
+
+ /**
+ * Ustvari novo abstraktno sintaksno drevo z dodanimi atributi izracuna
+ * pomnilniske predstavitve.
+ *
+ * @param attrAST Abstraktno sintaksno drevo z dodanimi atributi izracuna
+ * pomnilniske predstavitve.
+ */
+ public AttrAST(final AttrAST attrAST) {
+ super(attrAST);
+ this.attrFrame = attrAST.attrFrame;
+ this.attrParAccess = attrAST.attrParAccess;
+ this.attrVarAccess = attrAST.attrVarAccess;
+ }
+
+ @Override
+ public String head(final AST.Node node, final boolean highlighted) {
+ final StringBuffer head = new StringBuffer();
+ head.append(super.head(node, false));
+ head.append(highlighted ? "\033[31m" : "");
+ switch (node) {
+ case final AST.FunDef funDef:
+ Mem.Frame frame = attrFrame.get(funDef);
+ head.append(" depth=" + frame.depth);
+ head.append(" parsSize=" + frame.parsSize);
+ head.append(" varsSize=" + frame.varsSize);
+ break;
+ case final AST.ParDef parDef: {
+ Mem.RelAccess relAccess = attrParAccess.get(parDef);
+ head.append(" offset=" + relAccess.offset);
+ head.append(" size=" + relAccess.size);
+ head.append(" depth=" + relAccess.depth);
+ if (relAccess.inits != null)
+ initsToString(relAccess.inits, head);
+ break;
+ }
+ case final AST.VarDef varDef: {
+ Mem.Access access = attrVarAccess.get(varDef);
+ if (access != null)
+ switch (access) {
+ case final Mem.AbsAccess absAccess:
+ head.append(" size=" + absAccess.size);
+ if (absAccess.inits != null)
+ initsToString(absAccess.inits, head);
+ break;
+ case final Mem.RelAccess relAccess:
+ head.append(" offset=" + relAccess.offset);
+ head.append(" size=" + relAccess.size);
+ head.append(" depth=" + relAccess.depth);
+ if (relAccess.inits != null)
+ initsToString(relAccess.inits, head);
+ break;
+ default:
+ throw new Report.InternalError();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ head.append(highlighted ? "\033[30m" : "");
+ return head.toString();
+ }
+
+ /**
+ * Pripravi znakovno predstavitev zacetne vrednosti spremenmljivke.
+ *
+ * @param inits Zacetna vrednost spremenljivke.
+ * @param head Znakovno predstavitev zacetne vrednosti spremenmljivke.
+ */
+ private void initsToString(final List inits, final StringBuffer head) {
+ head.append(" inits=");
+ int numPrintedVals = 0;
+ int valPtr = 1;
+ for (int init = 0; init < inits.get(0); init++) {
+ final int num = inits.get(valPtr++);
+ final int len = inits.get(valPtr++);
+ int oldp = valPtr;
+ for (int n = 0; n < num; n++) {
+ valPtr = oldp;
+ for (int l = 0; l < len; l++) {
+ if (numPrintedVals == 10) {
+ head.append("...");
+ return;
+ }
+ head.append((numPrintedVals > 0 ? "," : "") + inits.get(valPtr++));
+ numPrintedVals++;
+ }
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Opravi izracun pomnilniske predstavitve.
+ *
+ * @param semanAttrAST Abstraktno sintaksno drevo z dodanimi atributi izracuna
+ * pomnilniske predstavitve.
+ * @return Abstraktno sintaksno drevo z atributi po fazi pomnilniske
+ * predstavitve.
+ */
+ public static AttrAST organize(SemAn.AttrAST semanAttrAST) {
+ AttrAST attrAST = new AttrAST(semanAttrAST, new HashMap(),
+ new HashMap(), new HashMap());
+ (new MemoryOrganizer(attrAST)).organize();
+ return attrAST;
+ }
+
+ /**
+ * Organizator pomnilniske predstavitve.
+ */
+ private static class MemoryOrganizer {
+
+ /**
+ * Abstraktno sintaksno drevo z dodanimi atributi izracuna pomnilniske
+ * predstavitve.
+ */
+ private final AttrAST attrAST;
+
+ /**
+ * Ustvari nov organizator pomnilniske predstavitve.
+ *
+ * @param attrAST Abstraktno sintaksno drevo z dodanimi atributi izracuna
+ * pomnilniske predstavitve.
+ */
+ public MemoryOrganizer(final AttrAST attrAST) {
+ this.attrAST = attrAST;
+ }
+
+ /**
+ * Sprozi nov izracun pomnilniske predstavitve.
+ *
+ * @return Abstraktno sintaksno drevo z dodanimi atributi izracuna pomnilniske
+ * predstavitve.
+ */
+ public AttrAST organize() {
+ attrAST.ast.accept(new MemoryVisitor(), null);
+ return new AttrAST(attrAST, Collections.unmodifiableMap(attrAST.attrFrame),
+ Collections.unmodifiableMap(attrAST.attrParAccess),
+ Collections.unmodifiableMap(attrAST.attrVarAccess));
+ }
+
+ static private class FrameBuilder {
+ int depth = 0;
+ int varOffset = 8; // FP + RA
+ Vector debugVars = new Vector<>();
+ }
+
+ /**
+ * Obiskovalec, ki izracuna pomnilnisko predstavitev.
+ */
+ private class MemoryVisitor implements AST.FullVisitor {
+
+ @SuppressWarnings({"doclint:missing"})
+ public MemoryVisitor() {
+ }
+
+ @Override
+ public FrameBuilder visit(AST.FunDef funDef, FrameBuilder upperFB) {
+ FrameBuilder frameBuilder = new FrameBuilder();
+ if (upperFB != null) {
+ frameBuilder.depth = upperFB.depth + 1;
+ }
+
+ int parOffset = 4; // +SL
+ Vector debugPars = new Vector<>();
+ for (AST.ParDef parDef : funDef.pars) {
+ Vector inits = new Vector<>();
+ inits.add(1);
+ inits.add(1);
+ inits.add(1);
+ inits.add(0);
+ Mem.RelAccess access = new Mem.RelAccess(parOffset, frameBuilder.depth, 4, inits, parDef.name);
+ parOffset += access.size;
+ debugPars.add(access);
+ attrAST.attrParAccess.put(parDef, access);
+ }
+
+ AST.FullVisitor.super.visit(funDef, frameBuilder);
+
+ Mem.Frame frame = new Mem.Frame(
+ funDef.name,
+ frameBuilder.depth,
+ parOffset,
+ frameBuilder.varOffset,
+ debugPars,
+ frameBuilder.debugVars
+ );
+ attrAST.attrFrame.put(funDef, frame);
+
+ return upperFB;
+ }
+
+ @Override
+ public FrameBuilder visit(AST.VarDef varDef, FrameBuilder frameBuilder) {
+ Vector inits = new Vector<>();
+ inits.add(varDef.inits.size());
+ for (AST.Init init : varDef.inits) {
+ Report.Locatable valLoc = attrAST.attrLoc.get(init.value);
+ Report.Locatable numLoc = attrAST.attrLoc.get(init.num);
+
+ inits.add(decodeIntConst(init.num, numLoc));
+
+ switch (init.value.type) {
+ case INTCONST:
+ inits.add(1);
+ inits.add(decodeIntConst(init.value, valLoc));
+ break;
+ case CHRCONST:
+ inits.add(1);
+ inits.add(decodeChrConst(init.value, valLoc));
+ break;
+ case STRCONST:
+ Vector str = decodeStrConst(init.value, valLoc);
+ inits.add(str.size());
+ inits.addAll(str);
+ break;
+ }
+ }
+
+ if (frameBuilder == null) {
+ Mem.AbsAccess access = new Mem.AbsAccess(varDef.name, inits.size(), inits);
+ attrAST.attrVarAccess.put(varDef, access);
+ } else {
+ Mem.RelAccess access = new Mem.RelAccess(frameBuilder.varOffset, frameBuilder.depth, inits.size(), inits, varDef.name);
+ frameBuilder.varOffset += inits.size();
+ frameBuilder.debugVars.add(access);
+ attrAST.attrVarAccess.put(varDef, access);
+ }
+
+ return frameBuilder;
+ }
+ }
+
+ }
+
+ /**
+ * Izracuna vrednost celostevilske konstante.
+ *
+ * @param intAtomExpr Celostevilska konstanta.
+ * @param loc Lokacija celostevilske konstante.
+ * @return Vrednost celostevilske konstante.
+ */
+ public static Integer decodeIntConst(final AST.AtomExpr intAtomExpr, final Report.Locatable loc) {
+ try {
+ return Integer.decode(intAtomExpr.value);
+ } catch (NumberFormatException __) {
+ throw new Report.Error(loc, "Illegal integer value.");
+ }
+ }
+
+ /**
+ * Izracuna vrednost znakovna konstante.
+ *
+ * @param chrAtomExpr Znakovna konstanta.
+ * @param loc Lokacija znakovne konstante.
+ * @return Vrednost znakovne konstante.
+ */
+ public static Integer decodeChrConst(final AST.AtomExpr chrAtomExpr, final Report.Locatable loc) {
+ switch (chrAtomExpr.value.charAt(1)) {
+ case '\\':
+ switch (chrAtomExpr.value.charAt(2)) {
+ case 'n':
+ return 10;
+ case '\'':
+ return ((int) '\'');
+ case '\\':
+ return ((int) '\\');
+ default:
+ return 16 * (((int) chrAtomExpr.value.charAt(2)) - ((int) '0'))
+ + (((int) chrAtomExpr.value.charAt(3)) - ((int) '0'));
+ }
+ default:
+ return ((int) chrAtomExpr.value.charAt(1));
+ }
+ }
+
+ /**
+ * Izracuna vrednost konstantnega niza.
+ *
+ * @param strAtomExpr Konstantni niz.
+ * @param loc Lokacija konstantnega niza.
+ * @return Vrendnost konstantega niza.
+ */
+ public static Vector decodeStrConst(final AST.AtomExpr strAtomExpr, final Report.Locatable loc) {
+ final Vector value = new Vector();
+ for (int c = 1; c < strAtomExpr.value.length() - 1; c++) {
+ switch (strAtomExpr.value.charAt(c)) {
+ case '\\':
+ switch (strAtomExpr.value.charAt(c + 1)) {
+ case 'n':
+ value.addLast(10);
+ c += 1;
+ break;
+ case '\"':
+ value.addLast((int) '\"');
+ c += 1;
+ break;
+ case '\\':
+ value.addLast((int) '\\');
+ c += 1;
+ break;
+ default:
+ value.addLast(16 * (((int) strAtomExpr.value.charAt(c + 1)) - ((int) '0'))
+ + (((int) strAtomExpr.value.charAt(c + 2)) - ((int) '0')));
+ c += 2;
+ break;
+ }
+ break;
+ default:
+ value.addLast((int) strAtomExpr.value.charAt(c));
+ break;
+ }
+ }
+ return value;
+ }
+
+ // --- ZAGON ---
+
+ /**
+ * Zagon izracuna pomnilniske predstavitve kot samostojnega programa.
+ *
+ * @param cmdLineArgs Argumenti v ukazni vrstici.
+ */
+ public static void main(final String[] cmdLineArgs) {
+ System.out.println("This is PINS'25 compiler (memory):");
+
+ try {
+ if (cmdLineArgs.length == 0)
+ throw new Report.Error("No source file specified in the command line.");
+ if (cmdLineArgs.length > 1)
+ Report.warning("Unused arguments in the command line.");
+
+ try (SynAn synAn = new SynAn(cmdLineArgs[0])) {
+ // abstraktna sintaksa:
+ final Abstr.AttrAST abstrAttrAST = Abstr.constructAST(synAn);
+ // semanticna analiza:
+ final SemAn.AttrAST semanAttrAST = SemAn.analyze(abstrAttrAST);
+ // pomnilniska predstavitev:
+ final AttrAST memoryAttrAST = Memory.organize(semanAttrAST);
+
+ (new AST.Logger(memoryAttrAST)).log();
+ }
+
+ // Upajmo, da kdaj pridemo to te tocke.
+ // A zavedajmo se sledecega:
+ // 1. Prevod je zaradi napak v programu lahko napacen :-o
+ // 2. Izvorni program se zdalec ni tisto, kar je programer hotel, da bi bil ;-)
+ Report.info("Done.");
+ } catch (Report.Error error) {
+ // Izpis opisa napake.
+ System.err.println(error.getMessage());
+ System.exit(1);
+ }
+ }
+
+}