/*
* File: ScriptInterpreter.java
* Author: Lukas K�nig
* Java version: 6.0
* Generated: 18.06.2008
*
* (c) Lukas K�nig, copyright according to GNU Lesser General Public License
* (LGPL) -> http://www.gnu.org/licenses/lgpl.html
*/
package fmg.fmg8.endlAutomat.script;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import fmg.fmg8.endlAutomat.EndlicherAutomat;
import fmg.fmg8.endlAutomat.Transition;
import fmg.fmg8.endlAutomat.ZInfo;
import fmg.fmg8.endlAutomat.conditions.Condition;
import fmg.fmg8.endlAutomat.conditions.ConstLeaf;
import fmg.fmg8.endlAutomat.conditions.InnerNode;
import fmg.fmg8.graphVis.graph.Knoten;
import fmg.fmg8.sonstiges.SonstMeth;
import fmg.fmg8.sonstiges.Zwischenablage;
import fmg.fmg8.statistik.Parametersatz;
/**
* Implements an interpreter for a script language for automata construction.
*
* @author Lukas K�nig
*/
public class ScriptInterpreter {
/**
* The instruction counter.
*/
private int instrCounter;
/**
* Counter.
*/
private int paramCounter;
/**
* Counter.
*/
private int ageCounter;
/**
* The parameters.
*/
private Parametersatz pars;
/**
* The current ScriptCondition.
*/
private ScriptCondition cond;
/**
* Der Modus, Verhalten oder Translator.
*/
private int modus;
/**
* Verhaltensautomaten-Modus.
*/
public static final int MODUS_VERHALTEN
= SonstMeth.MODUS_VERHALTEN;
/**
* �bersetzermodus.
*/
public static final int MODUS_TRANSLATOR
= SonstMeth.MODUS_TRANSLATOR;
/**
* Flag, dass markiert, ob gerade eine Bedingung existiert, die nicht
* einer Kante zugewiesen wurde.
*/
public boolean condWaiting;
/**
* Constructor.
*
* @param params The parameters.
* @param mod Der Modus (�bersetzer oder Verhalten).
*/
public ScriptInterpreter(
final Parametersatz params,
final int mod) {
this.pars = params;
this.cond = new ScriptCondition(this.pars, mod);
this.modus = mod;
this.reset();
}
/**
* Resets class vasiables.
*/
private void reset() {
this.instrCounter = 0;
this.paramCounter = 0;
this.ageCounter = 0;
this.condWaiting = false;
this.cond.reset();
}
/**
* @param num Number to normalize.
*
* @return Normalized number.
*/
private int normalize(final int num) {
int i = num % 256;
if (i <= 0) {
i = 1;
}
return i;
}
/**
* Inserts a node into the automaton.
*
* @param nam The name of the node.
* @param aut The automaton to be altered.
*/
private void insertNode(final int nam, final EndlicherAutomat aut) {
int aktion = SonstMeth.modZwischen(
this.instrCounter,
SonstMeth.minBef(this.modus),
SonstMeth.maxBef(this.modus));
int param = this.paramCounter % 256 + 1;
int alt = this.ageCounter % 256 + 1;
if (param == 256) {
param = 1;
}
if (alt == 256) {
alt = 1;
}
aut.einfuegenKnoten(nam, aktion, param, alt);
if (nam <= 0) {
throw new RuntimeException("Knoten " + nam + " nicht eingef�gt.");
}
if (aut.holeStartzustand() == null) {
aut.setStart(aut.holeKnoten(nam));
}
if (this.instrCounter
% (SonstMeth.maxBef(this.modus) - SonstMeth.minBef(this.modus) + 1)
== SonstMeth.maxBef(this.modus) - SonstMeth.minBef(this.modus)) {
this.paramCounter++;
}
if (this.paramCounter % 10 == 9) {
this.ageCounter++;
}
this.instrCounter++;
}
/**
* Inserts an edge.
*
* @param knotNam1 Source node.
* @param knotNam2 Target node.
* @param aut The automaton.
*/
private void insertEdge(final int knotNam1,
final int knotNam2,
final EndlicherAutomat aut) {
Knoten knot1 = aut.holeKnoten(knotNam1);
Knoten knot2 = aut.holeKnoten(knotNam2);
Condition c;
if (knot1 == null) {
this.insertNode(knotNam1, aut);
}
if (knot2 == null) {
this.insertNode(knotNam2, aut);
}
c = this.cond.getCondition();
aut.einfuegKante(knotNam1,
knotNam2,
c,
1);
this.cond.reset();
this.condWaiting = false;
this.instrCounter++;
}
/**
* Changes a part of a node.
*
* @param mode Denotes which part of the node should be changed.
* 1: instruction,
* 2: parameter,
* 3: additional parameter.
* @param knotNam Node to be changed.
* @param setValue Value to set.
* @param aut Automaton.
*/
private void changeNode(final int mode,
final int knotNam,
final int setValue,
final EndlicherAutomat aut) {
Knoten knot = aut.holeKnoten(knotNam);
ZInfo zusatz;
int set;
int setInst;
if (knot == null) {
this.insertNode(knotNam, aut);
knot = aut.holeKnoten(knotNam);
}
zusatz = knot.getInfo();
set = setValue % 256;
if (set == 0) {
set++;
}
if (mode == 1) { // Change instruction.
setInst = SonstMeth.modZwischen(
setValue,
SonstMeth.minBef(this.modus),
SonstMeth.maxBef(this.modus));
zusatz.setAkt(setInst);
}
if (mode == 2) { // Change parameter.
zusatz.setPar(set);
}
if (mode == 3) { // Change additional parameter.
zusatz.setAlter(set);
}
this.instrCounter++;
}
/**
* Adds a token to the current Condition. If condition is null, creates a
* new Condition.
*
* @param token The token to add.
*/
private void addCondTok(final Integer token) {
this.cond.addToken(token);
this.condWaiting = true;
}
/**
* F�gt eine Kante zwischen Quell- und Zielknoten ein, die die Bedingungen
* c1, c2, ... aller ausgehenden Kanten des Quellknotens erg�nzt durch die
* Bedingung: n(c1) & n(c2) & ...
* Die Bedingung wird vor dem Einf�gen vereinfacht. Falls die vereinfachte
* Bedingung <code>false</code> ist, wird keine Kante eingef�gt.
*
* @param qKnotNam Der Quellknoten, dessen Kanten erg�nzt werden
* sollen.
* @param zKnotNam Der Zielknoten, zu dem die erg�nzende Kante
* f�hren soll.
* @param aut Der zu ver�ndernde Automat.
*/
private void addComplCond(
final int qKnotNam,
final int zKnotNam,
final EndlicherAutomat aut) {
int quellKnotNam = qKnotNam, zielKnotNam = zKnotNam;
Knoten knot1;
Knoten knot2;
List<Transition> vorhTrans;
List<Condition> vorhConds;
Condition c;
Condition[] cZwisch;
ArrayList<Integer> knListe;
/* Falls eine Kante zwischen den Knoten bereits existierte, erzeuge
* eine Kante zwischen anderen (welchen?) Knoten... Zu �berpr�fen.
*/
if (aut.holeKnoten(qKnotNam) != null
&& aut.holeKnoten(qKnotNam).getInfo() != null
&& aut.holeKnoten(qKnotNam).holeNachfolger().containsKey(
zielKnotNam)) {
quellKnotNam = this.instrCounter;
this.instrCounter++;
zielKnotNam = this.instrCounter;
this.instrCounter++;
knListe = aut.getKnList();
quellKnotNam = knListe.get(
SonstMeth.modZwischen(quellKnotNam, 0, knListe.size() - 1));
zielKnotNam = knListe.get(
SonstMeth.modZwischen(zielKnotNam, 0, knListe.size() - 1));
// Wenn immer noch eine Kante existiert, f�ge nichts ein.
if (aut.holeKnoten(quellKnotNam) != null
&& aut.holeKnoten(quellKnotNam).getInfo() != null
&& aut.holeKnoten(quellKnotNam).holeNachfolger().containsKey(
zielKnotNam)) {
SonstMeth.log(
SonstMeth.LOG_STAGE1,
"Erg�nzungskante nicht eingef�gt, da die ersten beiden"
+ " Versuche bereits Kanten aufwiesen.",
this.pars);
return;
}
}
knot1 = aut.holeKnoten(quellKnotNam);
knot2 = aut.holeKnoten(zielKnotNam);
// F�ge Knoten neu ein, falls sie noch nicht existieren.
if (knot1 == null) {
this.insertNode(quellKnotNam, aut);
knot1 = aut.holeKnoten(quellKnotNam);
}
if (knot2 == null) {
this.insertNode(zielKnotNam, aut);
knot2 = aut.holeKnoten(zielKnotNam);
}
if (knot1.getInfo() == null || knot1.getInfo().getBeds().size() == 0) {
c = new ConstLeaf(true);
} else {
int i = 0;
vorhTrans = knot1.getInfo().getBeds();
vorhConds = new ArrayList<Condition>(vorhTrans.size());
for (Transition t : vorhTrans) {
vorhConds.add(t.getCond());
}
cZwisch = new Condition[vorhConds.size()];
for (Condition condition : vorhConds) {
cZwisch[i] = SonstMeth.ausFormatBed(condition.formatted());
cZwisch[i].negiere();
i++;
}
c = cZwisch[0];
for (int j = 1; j < cZwisch.length; j++) {
c = new InnerNode(
c,
cZwisch[j],
fmg.fmg8.endlAutomat.Konstanten.UND);
}
}
c = c.simplify();
// BO
// System.out.println();
// System.out.println(
// aut.holeKnoten(quellKnotNam).getInfo().getBedingungen());
// System.out.println(c);
// c = c;
// EO
if (!c.equals(new ConstLeaf(false))) {
aut.einfuegKante(
quellKnotNam,
zielKnotNam,
c,
1);
}
}
/**
* Executes the instruction on the specified automaton.
*
* - k(x) : Inserts node x.
* - b(x, y): Inserts node x if it does not exist; then changes the
* instruction of x to y.
* - p(x, y): Like b(x, y), but for parameter.
* - z(x, y): Like b(x, y), but for additional parameter.
* - T(x) : Adds a token to the current condition. If the current
* condition is null, creates one.
* - K(x, y): Inserts transition from x to y with corrent Condition;
* Condition == null => Generate "false"
* if x or y do not exist, creates them; sets current
* Condition to null.
* - E(x, y): Inserts a transition from x to y completing all current
* transitions of x.
*
* @param aut The automaton to be altered.
* @param inst The Instruction to be executed.
*/
private void execute(final EndlicherAutomat aut,
final ScriptInstruction inst) {
int instName = this.normalize(inst.getInstName());
int[] parameters = new int[inst.getInstParam().length];
for (int i = 0; i < parameters.length; i++) {
parameters[i] = this.normalize(inst.getInstParam()[i]);
}
if (inst.getInstName() == 0) { // Insert node.
this.insertNode(parameters[0], aut);
} else if (instName == 1
|| instName == 2
|| instName == 3) { // Change part of node.
int mode = instName;
int knotNam = parameters[0];
int setValue = parameters[1];
this.changeNode(mode, knotNam, setValue, aut);
} else if (instName == 4) { // Insert transition.
this.insertEdge(parameters[0],
parameters[1],
aut);
} else if (instName == 5) { // Begin condition.
this.addCondTok(inst.getInstParam()[0]);
} else if (instName == 6) { // Insert completing transition.
this.addComplCond(parameters[0], parameters[1], aut);
}
}
/**
* Generates an automaton based on the assigned Script.
*
* @param aut The automaton to construct.
* @param script The script which the construction is based on.
*/
public void generateAutomaton(
final EndlicherAutomat aut,
final Script script) {
Iterator<ScriptInstruction> it = script.iterator();
ScriptInstruction inst;
int knotNum1, knotNum2, knotNam1, knotNam2;
LinkedList<Integer> autKnoten;
SonstMeth.log(SonstMeth.LOG_STAGE1,
"Executing Script: "
+ script.toString().replace('\n', ' '),
this.pars);
this.reset();
aut.leereGraph();
while (it.hasNext()) {
inst = it.next();
this.execute(aut, inst);
// BO
// inst = inst;
// System.out.println("\n" + inst);
// System.out.println(aut.erzeugeSequenz().size());
// EO
}
// Falls noch eine Bedingung wartet, eine neue Kante einf�gen.
if (this.condWaiting) {
autKnoten = new LinkedList<Integer>(
aut.getAdjazenzliste().keySet());
knotNum1 = SonstMeth.modZwischen(
this.instrCounter,
0,
autKnoten.size());
knotNum2 = SonstMeth.modZwischen(
this.paramCounter,
0,
autKnoten.size());
if (knotNum1 > autKnoten.size() - 1) {
knotNam1 = knotNum1;
if (knotNam1 <= 0) {
knotNam1 = 255;
}
} else {
knotNam1 = autKnoten.get(knotNum1);
}
if (knotNum2 > autKnoten.size() - 1) {
knotNam2 = knotNum2;
if (knotNam2 <= 0) {
knotNam2 = 255;
}
} else {
knotNam2 = autKnoten.get(knotNum2);
}
this.insertEdge(
knotNam1,
knotNam2,
aut);
}
SonstMeth.log(SonstMeth.LOG_STAGE1,
"Script executed.",
this.pars);
SonstMeth.log(SonstMeth.LOG_STAGE1,
"Generated "
+ aut.getClass().getCanonicalName()
+ ".",
// + aut,
this.pars);
}
/**
* Test.
*
* @param args Nichts.
*/
public static void main(final String[] args) {
String[] p = {"log", "-1"};
Parametersatz pars = new Parametersatz(p);
ScriptInterpreter interp
= new ScriptInterpreter(pars, ScriptInterpreter.MODUS_VERHALTEN);
EndlicherAutomat a = new EndlicherAutomat(null, interp);
String str = "";
// for (int j = 0; j < 1000; j++) {
// str = str + (j % Const.BEF_PAR.length) + "," + j * (13 + j);
//
// if (Const.BEF_PAR[j % Const.BEF_PAR.length] == 2) {
// str = str + "," + (j + 1);
// }
//
// str = str + ";";
// }
//
str = "5, 422; 5, 4; 5, 232; 5, 239; 5, 293; 5, 1; 5, 262; ";
str += "5, 8; 4, 1, 2; 6, 1, 3; 5, 423; 4, 3, 4;";
str += "6, 3, 2; 6, 2, 3; 1, 2, 3;";
SonstMeth.log(SonstMeth.LOG_STAGE1, "Raw script: " + str, pars);
Script s = new Script(str);
interp.generateAutomaton(a, s);
(new Zwischenablage()).copyToClipboard(a.erzeugeStringSeq());
}
/**
* @return Returns the modus.
*/
public int getModus() {
return this.modus;
}
/**
* @param mod The modus to set.
*/
public void setModus(final int mod) {
this.modus = mod;
this.cond.setModus(mod);
}
}