Commit c8c3860e authored by Ludovic Apvrille's avatar Ludovic Apvrille

Adding save-result command

parent 1946bb0d
cd ~/TTool/bin&&java -Xmx2048m -jar ttool-cli.jar -debug -show script1
cd ~/TTool/bin&&java -Xmx2048m -jar ttool-cli.jar -debug -show z3script
......@@ -162,7 +162,7 @@
<infoparam name="Primitive port" value="Channel BEin" />
<TGConnectingPoint num="0" id="38" />
<extraparam>
<Prop commName="BEin" commType="0" origin="false" finite="false" blocking="true" maxSamples="8" widthSamples="4" isLossy="false" isPrex="false" isPostex="false" lossPercentage="0" maxNbOfLoss="0" dataFlowType="int16_t" associatedEvent="" checkConf="false" checkConfStatus="0" checkAuth="false" checkWeakAuthStatus="0" checkStrongAuthStatus="0" />
<Prop commName="BEin" commType="0" origin="false" finite="false" blocking="true" maxSamples="8" widthSamples="4" isLossy="false" isPrex="false" isPostex="false" lossPercentage="0" maxNbOfLoss="0" dataFlowType="int16_t" associatedEvent="" checkConf="false" checkConfStatus="0" checkAuth="false" checkWeakAuthStatus="0" checkStrongAuthStatus="0" vc="-1" />
<Type type="0" typeOther="" />
<Type type="0" typeOther="" />
<Type type="0" typeOther="" />
......@@ -179,7 +179,7 @@
<infoparam name="Primitive port" value="Channel DEin" />
<TGConnectingPoint num="0" id="40" />
<extraparam>
<Prop commName="DEin" commType="0" origin="false" finite="false" blocking="true" maxSamples="8" widthSamples="4" isLossy="false" isPrex="false" isPostex="false" lossPercentage="0" maxNbOfLoss="0" dataFlowType="int16_t" associatedEvent="" checkConf="false" checkConfStatus="0" checkAuth="false" checkWeakAuthStatus="0" checkStrongAuthStatus="0" />
<Prop commName="DEin" commType="0" origin="false" finite="false" blocking="true" maxSamples="8" widthSamples="4" isLossy="false" isPrex="false" isPostex="false" lossPercentage="0" maxNbOfLoss="0" dataFlowType="int16_t" associatedEvent="" checkConf="false" checkConfStatus="0" checkAuth="false" checkWeakAuthStatus="0" checkStrongAuthStatus="0" vc="-1" />
<Type type="0" typeOther="" />
<Type type="0" typeOther="" />
<Type type="0" typeOther="" />
......@@ -215,7 +215,7 @@
<infoparam name="Primitive port" value="Channel DEout" />
<TGConnectingPoint num="0" id="51" />
<extraparam>
<Prop commName="DEout" commType="0" origin="true" finite="false" blocking="true" maxSamples="8" widthSamples="4" isLossy="false" isPrex="false" isPostex="false" lossPercentage="0" maxNbOfLoss="0" dataFlowType="int16_t" associatedEvent="" checkConf="false" checkConfStatus="0" checkAuth="false" checkWeakAuthStatus="0" checkStrongAuthStatus="0" />
<Prop commName="DEout" commType="0" origin="true" finite="false" blocking="true" maxSamples="8" widthSamples="4" isLossy="false" isPrex="false" isPostex="false" lossPercentage="0" maxNbOfLoss="0" dataFlowType="int16_t" associatedEvent="" checkConf="false" checkConfStatus="0" checkAuth="false" checkWeakAuthStatus="0" checkStrongAuthStatus="0" vc="-1" />
<Type type="0" typeOther="" />
<Type type="0" typeOther="" />
<Type type="0" typeOther="" />
......@@ -232,7 +232,7 @@
<infoparam name="Primitive port" value="Channel ADin" />
<TGConnectingPoint num="0" id="53" />
<extraparam>
<Prop commName="ADin" commType="0" origin="false" finite="false" blocking="true" maxSamples="8" widthSamples="4" isLossy="false" isPrex="false" isPostex="false" lossPercentage="0" maxNbOfLoss="0" dataFlowType="int16_t" associatedEvent="" checkConf="false" checkConfStatus="0" checkAuth="false" checkWeakAuthStatus="0" checkStrongAuthStatus="0" />
<Prop commName="ADin" commType="0" origin="false" finite="false" blocking="true" maxSamples="8" widthSamples="4" isLossy="false" isPrex="false" isPostex="false" lossPercentage="0" maxNbOfLoss="0" dataFlowType="int16_t" associatedEvent="" checkConf="false" checkConfStatus="0" checkAuth="false" checkWeakAuthStatus="0" checkStrongAuthStatus="0" vc="-1" />
<Type type="0" typeOther="" />
<Type type="0" typeOther="" />
<Type type="0" typeOther="" />
......@@ -268,7 +268,7 @@
<infoparam name="Primitive port" value="Channel ABin" />
<TGConnectingPoint num="0" id="64" />
<extraparam>
<Prop commName="ABin" commType="0" origin="false" finite="false" blocking="true" maxSamples="8" widthSamples="4" isLossy="false" isPrex="false" isPostex="false" lossPercentage="0" maxNbOfLoss="0" dataFlowType="int16_t" associatedEvent="" checkConf="false" checkConfStatus="0" checkAuth="false" checkWeakAuthStatus="0" checkStrongAuthStatus="0" />
<Prop commName="ABin" commType="0" origin="false" finite="false" blocking="true" maxSamples="8" widthSamples="4" isLossy="false" isPrex="false" isPostex="false" lossPercentage="0" maxNbOfLoss="0" dataFlowType="int16_t" associatedEvent="" checkConf="false" checkConfStatus="0" checkAuth="false" checkWeakAuthStatus="0" checkStrongAuthStatus="0" vc="-1" />
<Type type="0" typeOther="" />
<Type type="0" typeOther="" />
<Type type="0" typeOther="" />
......@@ -285,7 +285,7 @@
<infoparam name="Primitive port" value="Channel BEout" />
<TGConnectingPoint num="0" id="66" />
<extraparam>
<Prop commName="BEout" commType="0" origin="true" finite="false" blocking="true" maxSamples="8" widthSamples="4" isLossy="false" isPrex="false" isPostex="false" lossPercentage="0" maxNbOfLoss="0" dataFlowType="int16_t" associatedEvent="" checkConf="false" checkConfStatus="0" checkAuth="false" checkWeakAuthStatus="0" checkStrongAuthStatus="0" />
<Prop commName="BEout" commType="0" origin="true" finite="false" blocking="true" maxSamples="8" widthSamples="4" isLossy="false" isPrex="false" isPostex="false" lossPercentage="0" maxNbOfLoss="0" dataFlowType="int16_t" associatedEvent="" checkConf="false" checkConfStatus="0" checkAuth="false" checkWeakAuthStatus="0" checkStrongAuthStatus="0" vc="-1" />
<Type type="0" typeOther="" />
<Type type="0" typeOther="" />
<Type type="0" typeOther="" />
......@@ -321,7 +321,7 @@
<infoparam name="Primitive port" value="Channel ADout" />
<TGConnectingPoint num="0" id="77" />
<extraparam>
<Prop commName="ADout" commType="0" origin="true" finite="false" blocking="true" maxSamples="8" widthSamples="4" isLossy="false" isPrex="false" isPostex="false" lossPercentage="0" maxNbOfLoss="0" dataFlowType="int16_t" associatedEvent="" checkConf="false" checkConfStatus="0" checkAuth="false" checkWeakAuthStatus="0" checkStrongAuthStatus="0" />
<Prop commName="ADout" commType="0" origin="true" finite="false" blocking="true" maxSamples="8" widthSamples="4" isLossy="false" isPrex="false" isPostex="false" lossPercentage="0" maxNbOfLoss="0" dataFlowType="int16_t" associatedEvent="" checkConf="false" checkConfStatus="0" checkAuth="false" checkWeakAuthStatus="0" checkStrongAuthStatus="0" vc="-1" />
<Type type="0" typeOther="" />
<Type type="0" typeOther="" />
<Type type="0" typeOther="" />
......@@ -338,7 +338,7 @@
<infoparam name="Primitive port" value="Channel ABout" />
<TGConnectingPoint num="0" id="79" />
<extraparam>
<Prop commName="ABout" commType="0" origin="true" finite="false" blocking="true" maxSamples="8" widthSamples="4" isLossy="false" isPrex="false" isPostex="false" lossPercentage="0" maxNbOfLoss="0" dataFlowType="int16_t" associatedEvent="" checkConf="false" checkConfStatus="0" checkAuth="false" checkWeakAuthStatus="0" checkStrongAuthStatus="0" />
<Prop commName="ABout" commType="0" origin="true" finite="false" blocking="true" maxSamples="8" widthSamples="4" isLossy="false" isPrex="false" isPostex="false" lossPercentage="0" maxNbOfLoss="0" dataFlowType="int16_t" associatedEvent="" checkConf="false" checkConfStatus="0" checkAuth="false" checkWeakAuthStatus="0" checkStrongAuthStatus="0" vc="-1" />
<Type type="0" typeOther="" />
<Type type="0" typeOther="" />
<Type type="0" typeOther="" />
......@@ -3667,9 +3667,9 @@
<SUBCOMPONENT type="1101" id="1758" >
<father id="1783" num="0" />
<cdparam x="747" y="169" />
<sizeparam width="112" height="40" minWidth="100" minHeight="1" maxWidth="2000" maxHeight="2000" minDesiredWidth="0" minDesiredHeight="0" />
<sizeparam width="107" height="40" minWidth="100" minHeight="1" maxWidth="2000" maxHeight="2000" minDesiredWidth="0" minDesiredHeight="0" />
<hidden value="false" />
<cdrectangleparam minX="0" maxX="38" minY="0" maxY="60" />
<cdrectangleparam minX="0" maxX="43" minY="0" maxY="60" />
<infoparam name="TGComponent" value="DEBA::taskD" />
<TGConnectingPoint num="0" id="1750" />
<TGConnectingPoint num="1" id="1751" />
......@@ -3794,9 +3794,9 @@
<SUBCOMPONENT type="1101" id="1842" >
<father id="1867" num="0" />
<cdparam x="581" y="169" />
<sizeparam width="111" height="40" minWidth="100" minHeight="1" maxWidth="2000" maxHeight="2000" minDesiredWidth="0" minDesiredHeight="0" />
<sizeparam width="105" height="40" minWidth="100" minHeight="1" maxWidth="2000" maxHeight="2000" minDesiredWidth="0" minDesiredHeight="0" />
<hidden value="false" />
<cdrectangleparam minX="0" maxX="39" minY="0" maxY="60" />
<cdrectangleparam minX="0" maxX="45" minY="0" maxY="60" />
<infoparam name="TGComponent" value="DEBA::taskE" />
<TGConnectingPoint num="0" id="1834" />
<TGConnectingPoint num="1" id="1835" />
......@@ -3849,9 +3849,9 @@
<SUBCOMPONENT type="1101" id="1876" >
<father id="1910" num="0" />
<cdparam x="1140" y="171" />
<sizeparam width="111" height="40" minWidth="100" minHeight="1" maxWidth="2000" maxHeight="2000" minDesiredWidth="0" minDesiredHeight="0" />
<sizeparam width="105" height="40" minWidth="100" minHeight="1" maxWidth="2000" maxHeight="2000" minDesiredWidth="0" minDesiredHeight="0" />
<hidden value="false" />
<cdrectangleparam minX="0" maxX="39" minY="0" maxY="60" />
<cdrectangleparam minX="0" maxX="45" minY="0" maxY="60" />
<infoparam name="TGComponent" value="DEBA::taskB" />
<TGConnectingPoint num="0" id="1868" />
<TGConnectingPoint num="1" id="1869" />
......@@ -3868,9 +3868,9 @@
<SUBCOMPONENT type="1101" id="1885" >
<father id="1910" num="1" />
<cdparam x="1140" y="145" />
<sizeparam width="111" height="40" minWidth="100" minHeight="1" maxWidth="2000" maxHeight="2000" minDesiredWidth="0" minDesiredHeight="0" />
<sizeparam width="106" height="40" minWidth="100" minHeight="1" maxWidth="2000" maxHeight="2000" minDesiredWidth="0" minDesiredHeight="0" />
<hidden value="false" />
<cdrectangleparam minX="0" maxX="39" minY="0" maxY="60" />
<cdrectangleparam minX="0" maxX="44" minY="0" maxY="60" />
<infoparam name="TGComponent" value="DEBA::taskA" />
<TGConnectingPoint num="0" id="1877" />
<TGConnectingPoint num="1" id="1878" />
......
......@@ -45,7 +45,11 @@ import myutil.FileUtils;
import myutil.PluginManager;
import myutil.TraceManager;
import tmltranslator.*;
import tmltranslator.dsez3engine.InputInstance;
import tmltranslator.dsez3engine.OptimizationModel;
import tmltranslator.dsez3engine.OptimizationResult;
import ui.MainGUI;
import ui.TGComponent;
import ui.TURTLEPanel;
import ui.util.IconManager;
......@@ -66,6 +70,8 @@ public class TML extends Command {
private TMLModeling tmlm;
private TMLMapping tmlmap;
private OptimizationResult result;
public TML() {
}
......@@ -116,6 +122,54 @@ public class TML extends Command {
};
subcommands.add(checkSyntax);
Command loadz3lib = new Command() {
public String getCommand() { return "loadz3lib"; }
public String getShortCommand() { return "z3lib"; }
public String getDescription() { return "Loading Z3 libs"; }
public String executeCommand(String command, Interpreter interpreter) {
//interpreter.print("Command=" + command);
return loadZ3lib(command);
}
};
subcommands.add(loadz3lib);
Command z3 = new Command() {
public String getCommand() { return "z3opt"; }
public String getShortCommand() { return "z3o"; }
public String getDescription() { return "Searching for an optimal mapping using Z3 (Z3 MUST be installed)"; }
public String executeCommand(String command, Interpreter interpreter) {
//interpreter.print("Command=" + command);
return z3OptimalMappingAnalysis();
}
};
subcommands.add(z3);
Command z3f = new Command() {
public String getCommand() { return "z3fea"; }
public String getShortCommand() { return "z3f"; }
public String getDescription() { return "Searching for a feasible mapping using Z3 (Z3 MUST be installed)"; }
public String executeCommand(String command, Interpreter interpreter) {
//interpreter.print("Command=" + command);
return z3FeasibleMappingAnalysis();
}
};
subcommands.add(z3f);
Command saveResult = new Command() {
public String getCommand() { return "save-result"; }
public String getShortCommand() { return "sr"; }
public String getDescription() { return "save result <file>: save results of a mapping exploration"; }
public String executeCommand(String command, Interpreter interpreter) {
//interpreter.print("Command=" + command);
return saveResult(command);
}
};
subcommands.add(saveResult);
}
......@@ -159,7 +213,7 @@ public class TML extends Command {
} catch (Exception e) {
return ("Exception during gile loading: " + e.getMessage());
return ("Exception during file loading: " + e.getMessage());
}
......@@ -215,12 +269,130 @@ public class TML extends Command {
syntax.checkSyntax();
if (syntax.hasErrors() == 0) {
if (syntax.hasErrors() > 0) {
return syntax.getErrors().size() + " errors found.";
}
return null;
}
private String loadZ3lib(String lib) {
try {
String [] libs = lib.split(":");
boolean setLibPath = false;
for (int i=0; i<libs.length; i++) {
// get the path and set it as a property of java lib path
String tmp = libs[i].trim();
if (tmp.length() > 0) {
if (setLibPath == false) {
File f = new File(tmp);
String dir = f.getParent();
//TraceManager.addDev("Old library path: " + System.getProperty("java.library.path"));
//TraceManager.addDev("Setting java library path to " + dir);
//System.setProperty("java.library.path", ".:" + dir);
ConfigurationTTool.addToJavaLibraryPath(new File(dir));
//TraceManager.addDev("New library path: " + System.getProperty("java.library.path"));
setLibPath = true;
}
TraceManager.addDev("Loading Z3 lib: " + tmp);
System.load(tmp);
TraceManager.addDev("Loaded Z3 lib: " + tmp);
}
}
} catch (UnsatisfiedLinkError e) {
return ("Z3 libs " + ConfigurationTTool.Z3LIBS + " could not be loaded");
}
return null;
}
private String z3OptimalMappingAnalysis() {
if (tmlmap == null) {
return "You must load a TML Mapping first";
}
if (tmlm == null) {
return "Empty task model";
}
@SuppressWarnings("unchecked")
InputInstance inputInstance = new InputInstance(tmlmap.getTMLArchitecture(), (TMLModeling<TGComponent>)tmlm);
OptimizationModel optimizationModel = new OptimizationModel(inputInstance);
//Loading Z3 libs;
//String error = ConfigurationTTool.loadZ3Libs();
try {
result = optimizationModel.findOptimizedMapping();
//result = optimizationModel.findFeasibleMapping();
} catch (Exception e) {
return("Exception during Z3 execution: Badly installed?");
}
return null;
}
private String z3FeasibleMappingAnalysis() {
if (tmlmap == null) {
return "You must load a TML Mapping first";
}
if (tmlm == null) {
return "Empty task model";
}
@SuppressWarnings("unchecked")
InputInstance inputInstance = new InputInstance(tmlmap.getTMLArchitecture(), (TMLModeling<TGComponent>)tmlm);
OptimizationModel optimizationModel = new OptimizationModel(inputInstance);
//Loading Z3 libs;
//String error = ConfigurationTTool.loadZ3Libs();
try {
//result = optimizationModel.findOptimizedMapping();
result = optimizationModel.findFeasibleMapping();
} catch (Exception e) {
return("Exception during Z3 execution: Badly installed?");
}
return null;
}
private String saveResult(String command) {
if (result == null) {
return "No result to save";
}
if (command.length() == 0) {
return "Must give a file as argument";
}
if (result.hasError()) {
return "No result to print since the exploration encountered errors";
}
File fileResult = new File(command);
try {
boolean b = FileUtils.checkFileForSave(fileResult);
if (!b) {
return "Results cannot be written to " + command + ": access denied";
}
FileUtils.saveFile(fileResult, result.result);
} catch (Exception e) {
return "Exception when writing results to file: " + e.getMessage();
}
return null;
}
}
......@@ -1713,11 +1713,13 @@ public class ConfigurationTTool {
}
TraceManager.addDev("Loading Z3 lib: " + tmp);
System.load(tmp);
TraceManager.addDev("Loaded Z3 lib: " + tmp);
}
}
} catch (UnsatisfiedLinkError e) {
return ("Z3 libs + " + ConfigurationTTool.Z3LIBS + " could not be loaded\n");
return ("Z3 libs " + ConfigurationTTool.Z3LIBS + " could not be loaded\n");
}
return null;
......
......@@ -72,7 +72,8 @@ public class TMLArchiTextSpecification {
private String keywords[] = {"NODE", "CPU", "FPGA", "SET", "BUS", "LINK", "BRIDGE", "ROUTER", "MEMORY", "MASTERCLOCKFREQUENCY", "DMA"};
private String nodetypes[] = {"CPU", "FPGA", "BUS", "LINK", "BRIDGE", "ROUTER", "MEMORY", "HWA", "DMA"};
private String cpuparameters[] = {"nbOfCores", "byteDataSize", "pipelineSize", "goIdleTime", "maxConsecutiveIdleCycles", "taskSwitchingTime", "branchingPredictionPenalty", "cacheMiss", "schedulingPolicy", "sliceTime", "execiTime", "execcTime"};
private String cpuparameters[] = {"nbOfCores", "byteDataSize", "pipelineSize", "goIdleTime", "maxConsecutiveIdleCycles", "taskSwitchingTime",
"branchingPredictionPenalty", "cacheMiss", "schedulingPolicy", "sliceTime", "execiTime", "execcTime", "operation"};
private String fpgaparameters[] = {"capacity", "byteDataSize", "mappingPenalty", "goIdleTime", "maxConsecutiveIdleCycles", "reconfigurationTime", "execiTime", "execcTime"};
private String linkparameters[] = {"bus", "node", "priority"};
private String hwaparameters[] = {"byteDataSize", "execiTime"};
......@@ -170,7 +171,9 @@ public class TMLArchiTextSpecification {
code += set + "sliceTime " + cpu.sliceTime + CR;
code += set + "execiTime " + cpu.execiTime + CR;
code += set + "execcTime " + cpu.execcTime + CR;
code += set + "operation " + cpu.getOperation() + CR;
if (cpu.getOperation().length() > 0) {
code += set + "operation " + cpu.getOperation() + CR;
}
}
// FPGA
......@@ -187,7 +190,9 @@ public class TMLArchiTextSpecification {
code += set + "reconfigurationTime " + fpga.reconfigurationTime + CR;
code += set + "execiTime " + fpga.execiTime + CR;
code += set + "execcTime " + fpga.execcTime + CR;
code += set + "operation " + fpga.getOperation() + CR;
if (fpga.getOperation().length() > 0) {
code += set + "operation " + fpga.getOperation() + CR;
}
}
......@@ -200,7 +205,9 @@ public class TMLArchiTextSpecification {
code += set + "byteDataSize " + hwa.byteDataSize + CR;
code += set + "execiTime " + hwa.execiTime + CR;
code += set + "execcTime " + hwa.execcTime + CR;
code += set + "operation " + hwa.getOperation() + CR;
if (hwa.getOperation().length() > 0) {
code += set + "operation " + hwa.getOperation() + CR;
}
}
// BUS
......@@ -442,9 +449,12 @@ public class TMLArchiTextSpecification {
return -1;
}
//TraceManager.addDev("NEW NODE =" + _split[1]);
if (_split[1].equals("CPU")) {
HwCPU cpu = new HwCPU(_split[2]);
tmla.addHwNode(cpu);
//TraceManager.addDev("Adding CPU:" + cpu.getName());
} else if (_split[1].equals("FPGA")) {
HwFPGA fpga = new HwFPGA(_split[2]);
tmla.addHwNode(fpga);
......@@ -476,7 +486,7 @@ public class TMLArchiTextSpecification {
// SET
if (isInstruction("SET", _split[0])) {
if (_split.length != 4) {
if (_split.length < 4) {
error = "A set instruction must be used with 3 parameters, and not " + (_split.length - 1);
addError(0, _lineNb, 0, error);
return -1;
......@@ -486,8 +496,14 @@ public class TMLArchiTextSpecification {
return -1;
}
HwNode node = tmla.getHwNodeByName(_split[1]);
HwLink link;
HwNode node = tmla.getHwNodeByName(_split[1]);
if (node != null) {
//TraceManager.addDev("Handling node=" + node.getName());
} else {
//TraceManager.addDev("Null node=" + _split[1]);
}
if (node == null) {
link = tmla.getHwLinkByName(_split[1]);
......@@ -497,6 +513,7 @@ public class TMLArchiTextSpecification {
return -1;
} else {
// Link node
if (link instanceof HwLink) {
if (!checkParameter("SET", _split, 2, 8, _lineNb)) {
return -1;
......@@ -537,14 +554,22 @@ public class TMLArchiTextSpecification {
if (node instanceof HwCPU) {
HwCPU cpu = (HwCPU) node;
//TraceManager.addDev("Seeting 1" + _split[2] + " in " + cpu.getName());
if (!checkParameter("SET", _split, 2, 3, _lineNb)) {
return -1;
}
if (!checkParameter("SET", _split, 3, 1, _lineNb)) {
return -1;
if (_split[2].toUpperCase().compareTo("OPERATION") != 0) {
if (!checkParameter("SET", _split, 3, 1, _lineNb)) {
return -1;
}
}
//TraceManager.addDev("Setting 2" + _split[2] + " in " + cpu.getName());
if (_split[2].toUpperCase().equals("NBOFCORES")) {
cpu.nbOfCores = Integer.decode(_split[3]).intValue();
}
......@@ -598,7 +623,7 @@ public class TMLArchiTextSpecification {
for (int i=3; i<_split.length; i++) {
tmpOp += _split[i] + " ";
}
//TraceManager.addDev("Setting op in " + cpu.getName() + " to " + tmpOp);
cpu.setOperation(tmpOp.trim());
}
}
......@@ -781,6 +806,7 @@ public class TMLArchiTextSpecification {
if (_split[2].toUpperCase().equals("NBOFCHANNELS")) {
dma.nbOfChannels = Integer.decode(_split[3]).intValue();
}
}
}
......
......@@ -39,6 +39,8 @@
package tmltranslator;
import myutil.TraceManager;
import java.util.ArrayList;
import java.util.List;
......@@ -282,7 +284,9 @@ public class TMLArchitecture {
public HwNode getHwNodeByName(String _name) {
for (HwNode node : hwnodes) {
if (node.getName().equals(_name)) {
//TraceManager.addDev("Comparing >" + node.getName() + "< vs >" + _name + "<");
if (node.getName().compareTo(_name) == 0) {
//TraceManager.addDev("Returning node " + node.getName());
return node;
}
}
......
......@@ -639,8 +639,8 @@ public class TMLMappingTextSpecification<E> {
// SET
if (isInstruction("SET", _split[0])) {
if (_split.length != 4) {
error = "A set instruction must be used with 3 parameters, and not " + (_split.length - 1);
if (_split.length < 4) {
error = "A set instruction must be used with at least 3 parameters, and not " + (_split.length - 1);
addError(0, _lineNb, 0, error, _line);
return -1;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment