cleanup of hgs parser, see #708

This commit is contained in:
hneemann 2021-04-13 10:24:53 +02:00
parent 45edbdf7c6
commit 3b6dffc335
2 changed files with 81 additions and 144 deletions

View File

@ -9,6 +9,7 @@ import de.neemann.digital.core.Bits;
import de.neemann.digital.hdl.hgs.function.FirstClassFunction;
import de.neemann.digital.hdl.hgs.function.FirstClassFunctionCall;
import de.neemann.digital.hdl.hgs.refs.*;
import de.neemann.digital.testing.parser.OperatorPrecedence;
import java.io.*;
import java.nio.charset.StandardCharsets;
@ -337,14 +338,6 @@ public class Parser {
return false;
}
private Tokenizer.Token nextIsIn(Tokenizer.Token... ts) throws IOException {
Tokenizer.Token next = tok.peek();
for (Tokenizer.Token t : ts)
if (next == t)
return tok.next();
return null;
}
private void expect(Tokenizer.Token token) throws IOException, ParserException {
Tokenizer.Token t = tok.next();
if (t != token)
@ -390,128 +383,26 @@ public class Parser {
}
private Expression parseExpression() throws IOException, ParserException {
Expression a = parseOR();
Tokenizer.Token t = nextIsIn(LESS, LESSEQUAL, EQUAL, NOTEQUAL, GREATER, GREATEREQUAL);
if (t != null) {
Expression b = parseOR();
switch (t) {
case EQUAL:
return c -> Value.equals(a.value(c), b.value(c));
case NOTEQUAL:
return c -> !Value.equals(a.value(c), b.value(c));
case LESS:
return c -> Value.less(a.value(c), b.value(c));
case LESSEQUAL:
return c -> Value.lessEqual(a.value(c), b.value(c));
case GREATER:
return c -> Value.less(b.value(c), a.value(c));
case GREATEREQUAL:
return c -> Value.lessEqual(b.value(c), a.value(c));
default:
throw newUnexpectedToken(t);
}
} else
return a;
return parseExpression(OperatorPrecedence.lowest());
}
private Expression parseOR() throws IOException, ParserException {
Expression ac = parseXOR();
while (nextIs(OR)) {
private Expression parseExpression(OperatorPrecedence op) throws IOException, ParserException {
Next next = getNextParser(op.getNextHigherPrecedence());
Expression ac = next.next();
while (tok.peek().getPrecedence() == op) {
Tokenizer.Binary function = tok.next().getBinary();
Expression a = ac;
Expression b = parseXOR();
ac = c -> Value.or(a.value(c), b.value(c));
Expression b = next.next();
ac = (c) -> function.op(a.value(c), b.value(c));
}
return ac;
}
private Expression parseXOR() throws IOException, ParserException {
Expression ac = parseAND();
while (nextIs(XOR)) {
Expression a = ac;
Expression b = parseAND();
ac = c -> Value.xor(a.value(c), b.value(c));
}
return ac;
}
private Expression parseAND() throws IOException, ParserException {
Expression ac = parseShiftRight();
while (nextIs(AND)) {
Expression a = ac;
Expression b = parseShiftRight();
ac = c -> Value.and(a.value(c), b.value(c));
}
return ac;
}
private Expression parseShiftRight() throws IOException, ParserException {
Expression ac = parseShiftLeft();
while (nextIs(SHIFTRIGHT)) {
Expression a = ac;
Expression b = parseShiftLeft();
ac = c -> Value.toLong(a.value(c)) >>> Value.toLong(b.value(c));
}
return ac;
}
private Expression parseShiftLeft() throws IOException, ParserException {
Expression ac = parseAdd();
while (nextIs(SHIFTLEFT)) {
Expression a = ac;
Expression b = parseAdd();
ac = c -> Value.toLong(a.value(c)) << Value.toLong(b.value(c));
}
return ac;
}
private Expression parseAdd() throws IOException, ParserException {
Expression ac = parseSub();
while (nextIs(ADD)) {
Expression a = ac;
Expression b = parseSub();
ac = c -> Value.add(a.value(c), b.value(c));
}
return ac;
}
private Expression parseSub() throws IOException, ParserException {
Expression ac = parseMul();
while (nextIs(SUB)) {
Expression a = ac;
Expression b = parseMul();
ac = c -> Value.sub(a.value(c), b.value(c));
}
return ac;
}
private Expression parseMul() throws IOException, ParserException {
Expression ac = parseDiv();
while (nextIs(MUL)) {
Expression a = ac;
Expression b = parseDiv();
ac = c -> Value.mul(a.value(c), b.value(c));
}
return ac;
}
private Expression parseDiv() throws IOException, ParserException {
Expression ac = parseMod();
while (nextIs(DIV)) {
Expression a = ac;
Expression b = parseMod();
ac = c -> Value.div(a.value(c), b.value(c));
}
return ac;
}
private Expression parseMod() throws IOException, ParserException {
Expression ac = parseIdent();
while (nextIs(MOD)) {
Expression a = ac;
Expression b = parseIdent();
ac = c -> Value.toLong(a.value(c)) % Value.toLong(b.value(c));
}
return ac;
private Next getNextParser(OperatorPrecedence pr) {
if (pr == null)
return this::parseIdent;
else
return () -> parseExpression(pr);
}
private Expression parseIdent() throws IOException, ParserException {
@ -602,6 +493,10 @@ public class Parser {
}
}
private interface Next {
Expression next() throws IOException, ParserException;
}
private FirstClassFunction parseFunction() throws IOException, ParserException {
expect(OPEN);
ArrayList<String> args = new ArrayList<>();

View File

@ -5,6 +5,8 @@
*/
package de.neemann.digital.hdl.hgs;
import de.neemann.digital.testing.parser.OperatorPrecedence;
import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
@ -14,36 +16,76 @@ import java.util.HashMap;
*/
class Tokenizer {
enum Token {
UNKNOWN, IDENT, AND, OR, XOR, NOT, OPEN, CLOSE, NUMBER, EOL, EOF, SHIFTLEFT, SHIFTRIGHT, COMMA, EQUAL,
ADD, SUB, MUL, GREATER, LESS, DIV, MOD, END, IF, ELSE, FOR, WHILE, SEMICOLON, NOTEQUAL, STRING,
OPENBRACE, CLOSEDBRACE, CODEEND, OPENSQUARE, CLOSEDSQUARE, DOT, FUNC, GREATEREQUAL, LESSEQUAL,
REPEAT, RETURN, COLON, UNTIL, DOUBLE, EXPORT, TRUE, FALSE
interface Binary {
Object op(Object a, Object b) throws HGSEvalException;
}
private static HashMap<String, Token> statementMap = new HashMap<>();
enum Token {
UNKNOWN, IDENT, OPEN, CLOSE, NUMBER, EOL, EOF, COMMA, NOT,
OR(OperatorPrecedence.OR, Value::or),
XOR(OperatorPrecedence.XOR, Value::xor),
AND(OperatorPrecedence.AND, Value::and),
EQUAL(OperatorPrecedence.EQUAL, Value::equals),
NOTEQUAL(OperatorPrecedence.EQUAL, (a, b) -> !Value.equals(a, b)),
ADD(OperatorPrecedence.ADD, Value::add),
SUB(OperatorPrecedence.ADD, Value::sub),
MUL(OperatorPrecedence.MUL, Value::mul),
DIV(OperatorPrecedence.MUL, Value::div),
MOD(OperatorPrecedence.MUL, (a, b) -> Value.toLong(a) % Value.toLong(b)),
LESS(OperatorPrecedence.COMPARE, Value::less),
LESSEQUAL(OperatorPrecedence.COMPARE, Value::lessEqual),
GREATER(OperatorPrecedence.COMPARE, (a, b) -> Value.less(b, a)),
GREATEREQUAL(OperatorPrecedence.COMPARE, (a, b) -> Value.lessEqual(b, a)),
SHIFTLEFT(OperatorPrecedence.SHIFT, (a, b) -> Value.toLong(a) << Value.toLong(b)),
SHIFTRIGHT(OperatorPrecedence.SHIFT, (a, b) -> Value.toLong(a) >>> Value.toLong(b)),
END, IF, ELSE, FOR, WHILE, SEMICOLON, STRING,
OPENBRACE, CLOSEDBRACE, CODEEND, OPENSQUARE, CLOSEDSQUARE, DOT, FUNC,
REPEAT, RETURN, COLON, UNTIL, DOUBLE, EXPORT, TRUE, FALSE;
private final OperatorPrecedence precedence;
private final Binary binary;
Token() {
this(null, null);
}
Token(OperatorPrecedence precedence, Binary binary) {
this.precedence = precedence;
this.binary = binary;
}
public OperatorPrecedence getPrecedence() {
return precedence;
}
public Binary getBinary() {
return binary;
}
}
private static final HashMap<String, Token> STATEMENT_MAP = new HashMap<>();
static {
statementMap.put("if", Token.IF);
statementMap.put("else", Token.ELSE);
statementMap.put("for", Token.FOR);
statementMap.put("while", Token.WHILE);
statementMap.put("func", Token.FUNC);
statementMap.put("repeat", Token.REPEAT);
statementMap.put("until", Token.UNTIL);
statementMap.put("return", Token.RETURN);
statementMap.put("export", Token.EXPORT);
statementMap.put("true", Token.TRUE);
statementMap.put("false", Token.FALSE);
STATEMENT_MAP.put("if", Token.IF);
STATEMENT_MAP.put("else", Token.ELSE);
STATEMENT_MAP.put("for", Token.FOR);
STATEMENT_MAP.put("while", Token.WHILE);
STATEMENT_MAP.put("func", Token.FUNC);
STATEMENT_MAP.put("repeat", Token.REPEAT);
STATEMENT_MAP.put("until", Token.UNTIL);
STATEMENT_MAP.put("return", Token.RETURN);
STATEMENT_MAP.put("export", Token.EXPORT);
STATEMENT_MAP.put("true", Token.TRUE);
STATEMENT_MAP.put("false", Token.FALSE);
}
private final Reader in;
private final StringBuilder builder;
private final String srcFile;
private Token token;
private boolean isToken;
private StringBuilder builder;
private boolean isUnreadChar = false;
private int unreadChar;
private String srcFile;
private int line = 1;
/**
@ -301,7 +343,7 @@ class Tokenizer {
wasChar = false;
}
} while (wasChar);
token = statementMap.get(builder.toString());
token = STATEMENT_MAP.get(builder.toString());
if (token == null) token = Token.IDENT;
}
@ -394,7 +436,7 @@ class Tokenizer {
isToken = false;
StringBuilder sb = new StringBuilder();
int c;
while ((c = readChar())>0) {
while ((c = readChar()) > 0) {
if (c == '<' || c == '{') {
if (isNextChar('?')) {
return sb.toString();