some cleanup

This commit is contained in:
hneemann 2018-03-15 13:00:10 +01:00
parent 1e29779cbb
commit 4c654fdb60
4 changed files with 127 additions and 83 deletions

View File

@ -56,8 +56,8 @@ public class Parser {
String text = tok.readText();
if (text.length() > 0)
s.add(c -> c.print(text));
while (!isToken(EOF)) {
if (isToken(STATIC)) {
while (!nextIs(EOF)) {
if (nextIs(STATIC)) {
Statement stat = parseStatement();
try {
stat.execute(staticContext);
@ -81,51 +81,57 @@ public class Parser {
return parseStatement(true);
}
private Statement parseStatement(boolean semicolon) throws IOException, ParserException {
if (isToken(IDENT)) {
/**
* If 'isRealStatement' is false, the statement is parsed like an expression.
* This mode is needed to implement the 'for' loop. In a C style for loop the pre and the
* post code are expressions, which modify state, which is not supported by HGS. In the HGS
* for loop the pre and the post code are statements where the semicolon at the end is omitted.
*/
private Statement parseStatement(boolean isRealStatement) throws IOException, ParserException {
if (nextIs(IDENT)) {
Reference ref = parseReference(tok.getIdent());
if (isToken(EQUAL)) {
if (nextIs(EQUAL)) {
Expression val = parseExpression();
if (semicolon) expect(SEMICOLON);
if (isRealStatement) expect(SEMICOLON);
return c -> ref.set(c, val.value(c));
} else if (isToken(ADD)) {
} else if (nextIs(ADD)) {
expect(ADD);
if (semicolon) expect(SEMICOLON);
if (isRealStatement) expect(SEMICOLON);
return c -> ref.set(c, Value.toLong(ref.get(c)) + 1);
} else if (isToken(SUB)) {
} else if (nextIs(SUB)) {
expect(SUB);
if (semicolon) expect(SEMICOLON);
if (isRealStatement) expect(SEMICOLON);
return c -> ref.set(c, Value.toLong(ref.get(c)) - 1);
} else if (isToken(SEMICOLON)) {
} else if (nextIs(SEMICOLON)) {
return ref::get;
} else
throw newUnexpectedToken(tok.next());
} else if (isToken(CODEEND)) {
} else if (nextIs(CODEEND)) {
String str = tok.readText();
return c -> c.print(str);
} else if (isToken(EQUAL)) {
} else if (nextIs(EQUAL)) {
Expression exp = parseExpression();
if (tok.peek() != CODEEND) expect(SEMICOLON);
return c -> c.print(exp.value(c).toString());
} else if (isToken(PRINT)) {
} else if (nextIs(PRINT)) {
expect(OPEN);
ArrayList<Expression> args = parseArgList();
if (semicolon) expect(SEMICOLON);
if (isRealStatement) expect(SEMICOLON);
return c -> {
for (Expression e : args)
c.print(e.value(c).toString());
};
} else if (isToken(PRINTF)) {
} else if (nextIs(PRINTF)) {
expect(OPEN);
ArrayList<Expression> args = parseArgList();
if (semicolon) expect(SEMICOLON);
if (isRealStatement) expect(SEMICOLON);
return c -> c.print(FunctionFormat.format(c, args));
} else if (isToken(IF)) {
} else if (nextIs(IF)) {
expect(OPEN);
Expression cond = parseExpression();
expect(CLOSE);
Statement ifPart = parseStatement();
if (isToken(ELSE)) {
if (nextIs(ELSE)) {
Statement elsePart = parseStatement();
return c -> {
if (Value.toBool(cond.value(c)))
@ -138,14 +144,13 @@ public class Parser {
if (Value.toBool(cond.value(c)))
ifPart.execute(c);
};
} else if (isToken(FOR)) {
} else if (nextIs(FOR)) {
expect(OPEN);
Statement init = parseStatement(false);
Statement init = parseStatement(false); // parse like an expression
expect(SEMICOLON);
Expression cond = parseExpression();
expect(SEMICOLON);
Statement inc = parseStatement(false);
Statement inc = parseStatement(false); // parse like an expression
expect(CLOSE);
Statement inner = parseStatement();
return c -> {
@ -155,16 +160,24 @@ public class Parser {
inc.execute(c);
}
};
} else if (isToken(OPENBRACE)) {
} else if (nextIs(WHILE)) {
expect(OPEN);
Expression cond = parseExpression();
expect(CLOSE);
Statement inner = parseStatement();
return c -> {
while (Value.toBool(cond.value(c))) inner.execute(c);
};
} else if (nextIs(OPENBRACE)) {
Statements s = new Statements();
while (!isToken(CLOSEDBRACE))
while (!nextIs(CLOSEDBRACE))
s.add(parseStatement());
return s.optimize();
} else if (isToken(PANIC)) {
} else if (nextIs(PANIC)) {
expect(OPEN);
Expression message = parseExpression();
expect(CLOSE);
if (semicolon) expect(SEMICOLON);
if (isRealStatement) expect(SEMICOLON);
return c -> {
throw new HGSEvalException(message.value(c).toString());
};
@ -174,9 +187,9 @@ public class Parser {
private ArrayList<Expression> parseArgList() throws IOException, ParserException {
ArrayList<Expression> args = new ArrayList<>();
if (!isToken(CLOSE)) {
if (!nextIs(CLOSE)) {
args.add(parseExpression());
while (isToken(COMMA))
while (nextIs(COMMA))
args.add(parseExpression());
expect(CLOSE);
}
@ -186,14 +199,14 @@ public class Parser {
private Reference parseReference(String var) throws IOException, ParserException {
Reference r = new ReferenceToVar(var);
while (true) {
if (isToken(OPENSQUARE)) {
if (nextIs(OPENSQUARE)) {
Expression index = parseExpression();
expect(CLOSEDSQUARE);
r = new ReferenceToArray(r, index);
} else if (isToken(OPEN)) {
} else if (nextIs(OPEN)) {
ArrayList<Expression> args = parseArgList();
r = new ReferenceToFunc(r, args);
} else if (isToken(DOT)) {
} else if (nextIs(DOT)) {
expect(IDENT);
r = new ReferenceToStruct(r, tok.getIdent());
} else
@ -201,7 +214,7 @@ public class Parser {
}
}
private boolean isToken(Tokenizer.Token t) throws IOException {
private boolean nextIs(Tokenizer.Token t) throws IOException {
if (tok.peek() == t) {
tok.next();
return true;
@ -247,7 +260,7 @@ public class Parser {
private Expression parseExpression() throws IOException, ParserException {
Expression ac = parseLessEquals();
while (isToken(Tokenizer.Token.LESS)) {
while (nextIs(Tokenizer.Token.LESS)) {
Expression a = ac;
Expression b = parseLessEquals();
ac = c -> Value.toLong(a.value(c)) < Value.toLong(b.value(c));
@ -257,7 +270,7 @@ public class Parser {
private Expression parseLessEquals() throws IOException, ParserException {
Expression ac = parseGreater();
while (isToken(Tokenizer.Token.LESSEQUAL)) {
while (nextIs(Tokenizer.Token.LESSEQUAL)) {
Expression a = ac;
Expression b = parseGreater();
ac = c -> Value.toLong(a.value(c)) <= Value.toLong(b.value(c));
@ -267,7 +280,7 @@ public class Parser {
private Expression parseGreater() throws IOException, ParserException {
Expression ac = parseGreaterEquals();
while (isToken(Tokenizer.Token.GREATER)) {
while (nextIs(Tokenizer.Token.GREATER)) {
Expression a = ac;
Expression b = parseGreaterEquals();
ac = c -> Value.toLong(a.value(c)) > Value.toLong(b.value(c));
@ -277,7 +290,7 @@ public class Parser {
private Expression parseGreaterEquals() throws IOException, ParserException {
Expression ac = parseEquals();
while (isToken(Tokenizer.Token.GREATEREQUAL)) {
while (nextIs(Tokenizer.Token.GREATEREQUAL)) {
Expression a = ac;
Expression b = parseEquals();
ac = c -> Value.toLong(a.value(c)) >= Value.toLong(b.value(c));
@ -287,7 +300,7 @@ public class Parser {
private Expression parseEquals() throws IOException, ParserException {
Expression ac = parseNotEquals();
while (isToken(Tokenizer.Token.EQUAL)) {
while (nextIs(Tokenizer.Token.EQUAL)) {
Expression a = ac;
Expression b = parseNotEquals();
ac = c -> Value.equals(a.value(c), b.value(c));
@ -297,7 +310,7 @@ public class Parser {
private Expression parseNotEquals() throws IOException, ParserException {
Expression ac = parseOR();
while (isToken(Tokenizer.Token.NOTEQUAL)) {
while (nextIs(Tokenizer.Token.NOTEQUAL)) {
Expression a = ac;
Expression b = parseOR();
ac = c -> !Value.equals(a.value(c), b.value(c));
@ -307,7 +320,7 @@ public class Parser {
private Expression parseOR() throws IOException, ParserException {
Expression ac = parseXOR();
while (isToken(Tokenizer.Token.OR)) {
while (nextIs(Tokenizer.Token.OR)) {
Expression a = ac;
Expression b = parseXOR();
ac = c -> Value.or(a.value(c), b.value(c));
@ -317,7 +330,7 @@ public class Parser {
private Expression parseXOR() throws IOException, ParserException {
Expression ac = parseAND();
while (isToken(Tokenizer.Token.XOR)) {
while (nextIs(Tokenizer.Token.XOR)) {
Expression a = ac;
Expression b = parseAND();
ac = c -> Value.xor(a.value(c), b.value(c));
@ -327,7 +340,7 @@ public class Parser {
private Expression parseAND() throws IOException, ParserException {
Expression ac = parseShiftRight();
while (isToken(Tokenizer.Token.AND)) {
while (nextIs(Tokenizer.Token.AND)) {
Expression a = ac;
Expression b = parseShiftRight();
ac = c -> Value.and(a.value(c), b.value(c));
@ -337,7 +350,7 @@ public class Parser {
private Expression parseShiftRight() throws IOException, ParserException {
Expression ac = parseShiftLeft();
while (isToken(Tokenizer.Token.SHIFTRIGHT)) {
while (nextIs(Tokenizer.Token.SHIFTRIGHT)) {
Expression a = ac;
Expression b = parseShiftLeft();
ac = c -> Value.toLong(a.value(c)) >> Value.toLong(b.value(c));
@ -347,7 +360,7 @@ public class Parser {
private Expression parseShiftLeft() throws IOException, ParserException {
Expression ac = parseAdd();
while (isToken(Tokenizer.Token.SHIFTLEFT)) {
while (nextIs(Tokenizer.Token.SHIFTLEFT)) {
Expression a = ac;
Expression b = parseAdd();
ac = c -> Value.toLong(a.value(c)) << Value.toLong(b.value(c));
@ -357,7 +370,7 @@ public class Parser {
private Expression parseAdd() throws IOException, ParserException {
Expression ac = parseSub();
while (isToken(Tokenizer.Token.ADD)) {
while (nextIs(Tokenizer.Token.ADD)) {
Expression a = ac;
Expression b = parseSub();
ac = c -> Value.add(a.value(c), b.value(c));
@ -367,7 +380,7 @@ public class Parser {
private Expression parseSub() throws IOException, ParserException {
Expression ac = parseMul();
while (isToken(Tokenizer.Token.SUB)) {
while (nextIs(Tokenizer.Token.SUB)) {
Expression a = ac;
Expression b = parseMul();
ac = c -> Value.toLong(a.value(c)) - Value.toLong(b.value(c));
@ -377,7 +390,7 @@ public class Parser {
private Expression parseMul() throws IOException, ParserException {
Expression ac = parseDiv();
while (isToken(Tokenizer.Token.MUL)) {
while (nextIs(Tokenizer.Token.MUL)) {
Expression a = ac;
Expression b = parseDiv();
ac = c -> Value.toLong(a.value(c)) * Value.toLong(b.value(c));
@ -387,7 +400,7 @@ public class Parser {
private Expression parseDiv() throws IOException, ParserException {
Expression ac = parseMod();
while (isToken(Tokenizer.Token.DIV)) {
while (nextIs(Tokenizer.Token.DIV)) {
Expression a = ac;
Expression b = parseMod();
ac = c -> Value.toLong(a.value(c)) / Value.toLong(b.value(c));
@ -397,7 +410,7 @@ public class Parser {
private Expression parseMod() throws IOException, ParserException {
Expression ac = parseIdent();
while (isToken(Tokenizer.Token.MOD)) {
while (nextIs(Tokenizer.Token.MOD)) {
Expression a = ac;
Expression b = parseIdent();
ac = c -> Value.toLong(a.value(c)) % Value.toLong(b.value(c));
@ -439,10 +452,10 @@ public class Parser {
private FirstClassFunction parseFunction() throws IOException, ParserException {
expect(OPEN);
ArrayList<String> args = new ArrayList<>();
if (!isToken(CLOSE)) {
if (!nextIs(CLOSE)) {
expect(IDENT);
args.add(tok.getIdent());
while (!isToken(CLOSE)) {
while (!nextIs(CLOSE)) {
expect(COMMA);
expect(IDENT);
args.add(tok.getIdent());

View File

@ -26,7 +26,7 @@ class Tokenizer {
statementMap.put("if", Token.IF);
statementMap.put("else", Token.ELSE);
statementMap.put("for", Token.FOR);
statementMap.put("while", Token.FOR);
statementMap.put("while", Token.WHILE);
statementMap.put("print", Token.PRINT);
statementMap.put("printf", Token.PRINTF);
statementMap.put("func", Token.FUNC);

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2018 Helmut Neemann.
* Use of this source code is governed by the GPL v3 license
* that can be found in the LICENSE file.
*/
package de.neemann.digital.core.element;
import de.neemann.digital.core.memory.DataField;
import de.neemann.digital.hdl.hgs.Context;
import de.neemann.digital.hdl.hgs.HGSEvalException;
import de.neemann.digital.hdl.hgs.Parser;
import de.neemann.digital.hdl.hgs.ParserException;
import junit.framework.TestCase;
import java.io.IOException;
public class ElementAttributesTest extends TestCase {
/**
* Ensures that the ElementAtributes is accessible from within the template engine
*/
public void testElementAttibutes() throws IOException, ParserException, HGSEvalException {
ElementAttributes attr = new ElementAttributes().set(Keys.BITS, 5);
final Context c = new Context().setVar("elem", attr);
new Parser("bits=<?=elem.Bits?>;").parse().execute(c);
assertEquals("bits=5;", c.toString());
}
/**
* Ensures that the DataField is accessible from within the template engine
*/
public void testDataField() throws IOException, ParserException, HGSEvalException {
DataField d = new DataField(5)
.setData(0, 1)
.setData(1, 7)
.setData(2, 4)
.setData(3, 8)
.setData(4, 2);
Context c= new Context().setVar("d", d);
new Parser("(<? for(i=0;i<sizeOf(d);i++) { if (i>0) print(\"-\"); print(d[i]);} ?>)").parse().execute(c);
assertEquals("(1-7-4-8-2)", c.toString());
}
}

View File

@ -5,9 +5,6 @@
*/
package de.neemann.digital.hdl.hgs;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.Keys;
import de.neemann.digital.core.memory.DataField;
import de.neemann.digital.hdl.hgs.function.FirstClassFunction;
import de.neemann.digital.hdl.hgs.function.FuncAdapter;
import de.neemann.digital.integration.FileScanner;
@ -150,6 +147,8 @@ public class ParserTest extends TestCase {
assertEquals("Hello -4-5- World!", c.toString());
}
// for statement
public void testParseTemplateFor() throws IOException, ParserException, HGSEvalException {
Context c = exec("Hello <? for (i=0;i<10;i++) print(i); ?> World!");
assertEquals("Hello 0123456789 World!", c.toString());
@ -178,30 +177,11 @@ public class ParserTest extends TestCase {
assertEquals("Hello (12)(24)(36) World!", c.toString());
}
// while statement
public void testParseTemplateElementAttibutes() throws IOException, ParserException, HGSEvalException {
ElementAttributes attr = new ElementAttributes().set(Keys.BITS, 5);
Context c = exec("bits=<?=elem.Bits?>;", new Context().setVar("elem", attr));
assertEquals("bits=5;", c.toString());
}
public void testParseTemplateDataField() throws IOException, ParserException, HGSEvalException {
DataField d = new DataField(5)
.setData(0, 1)
.setData(1, 7)
.setData(2, 4)
.setData(3, 8)
.setData(4, 2);
Context c = exec("(<? for(i=0;i<sizeOf(d);i++) { if (i>0) print(\"-\"); print(d[i]);} ?>)",
new Context().setVar("d", d));
assertEquals("(1-7-4-8-2)", c.toString());
}
public void testParseTemplateFormat() throws IOException, ParserException, HGSEvalException {
ElementAttributes attr = new ElementAttributes().set(Keys.BITS, 17);
Context c = new Context().setVar("elem", attr);
exec("<? a=format(\"hex=%x;\",elem.Bits); print(a);?>", c);
assertEquals("hex=11;", c.toString());
public void testParseTemplateWhile() throws IOException, ParserException, HGSEvalException {
Context c = exec("Hello <? i=0; while (i<=9) { =i; i++; } ?> World!");
assertEquals("Hello 0123456789 World!", c.toString());
}
public void testParseTemplateArray() throws IOException, ParserException, HGSEvalException {
@ -249,13 +229,19 @@ public class ParserTest extends TestCase {
assertEquals("4;", exec(t, new Context().setVar("m", 4)).toString());
}
public void testParseTemplateFormat() throws IOException, ParserException, HGSEvalException {
Context c = new Context().setVar("Bits", 17);
exec("<? a=format(\"hex=%x;\",Bits); print(a);?>", c);
assertEquals("hex=11;", c.toString());
}
public void testComment() throws IOException, ParserException, HGSEvalException {
Context c = exec("<? // comment\nprint(\"false\"); // zzz\n ?>;");
assertEquals("false;", c.toString());
}
public void testAddFunction() throws IOException, ParserException, HGSEvalException {
Statement s = new Parser("a : in <?=type(elem.Bits)?>;").parse();
Statement s = new Parser("a : in <?=type(Bits)?>;").parse();
Context funcs = new Context().setVar("type", new FuncAdapter(1) {
@Override
protected Object f(Object... args) throws HGSEvalException {
@ -268,10 +254,10 @@ public class ParserTest extends TestCase {
});
assertEquals("a : in std_logic;",
exec(s, new Context(funcs)
.setVar("elem", new ElementAttributes())).toString());
.setVar("Bits", 1)).toString());
assertEquals("a : in std_logic_vector(5 downto 0);",
exec(s, new Context(funcs)
.setVar("elem", new ElementAttributes().setBits(6))).toString());
.setVar("Bits", 6)).toString());
}
int flag = 0;
@ -339,10 +325,11 @@ public class ParserTest extends TestCase {
}
}
// checks the available VHDL templates
public void testVHDLTemplates() throws Exception {
final File path = new File(Resources.getRoot(), "../../main/resources/vhdl");
int n=new FileScanner(f -> new Parser(new FileReader(f)).parse()).setSuffix(".tem").scan(path);
assertTrue(n>10);
int n = new FileScanner(f -> new Parser(new FileReader(f)).parse()).setSuffix(".tem").scan(path);
assertTrue(n > 10);
}
}