From ba776b8ba4a1a189706768b55e9d8f7042076c3d Mon Sep 17 00:00:00 2001 From: hneemann Date: Wed, 19 Apr 2017 16:41:41 +0200 Subject: [PATCH] simplified test data parser --- .../digital/testing/parser/Parser.java | 99 +++++++++---------- .../digital/testing/parser/Tokenizer.java | 17 +++- .../testing/parser/ParserLoopTest.java | 10 +- 3 files changed, 69 insertions(+), 57 deletions(-) diff --git a/src/main/java/de/neemann/digital/testing/parser/Parser.java b/src/main/java/de/neemann/digital/testing/parser/Parser.java index 7a9a1734f..1043f8a67 100644 --- a/src/main/java/de/neemann/digital/testing/parser/Parser.java +++ b/src/main/java/de/neemann/digital/testing/parser/Parser.java @@ -43,7 +43,7 @@ public class Parser { */ public Parser parse() throws IOException, ParserException { parseHeader(); - emitter = parseValues(false); + emitter = parseRows(false); expect(Tokenizer.Token.EOF); return this; } @@ -69,7 +69,7 @@ public class Parser { return new ParserException(Lang.get("err_unexpectedToken_N0_inLine_N1", name, tok.getLine())); } - private LineEmitter parseValues(boolean loop) throws IOException, ParserException { + private LineEmitter parseRows(boolean loop) throws IOException, ParserException { LineEmitterList list = new LineEmitterList(); while (true) { Tokenizer.Token t = tok.peek(); @@ -80,40 +80,38 @@ public class Parser { if (loop) throw newUnexpectedToken(t); return list.minimize(); - case NUMBER: - list.add(parseLine()); - break; + case BITS: + case OPEN: case IDENT: - if (tok.getIdent().equals("end")) { - tok.consume(); - expect(Tokenizer.Token.IDENT); - if (!tok.getIdent().equals("loop")) - throw newUnexpectedToken(t); - if (!loop) - throw newUnexpectedToken(t); - return list.minimize(); - } else if (tok.getIdent().equals("repeat")) { - tok.consume(); - expect(Tokenizer.Token.OPEN); - int count = (int) parseInt(); - if (count > 1 << 16) - throw new ParserException(Lang.get("err_toManyTestEntries")); - expect(Tokenizer.Token.CLOSE); - list.add(new LineEmitterRepeat("n", count, parseLine())); - } else if (tok.getIdent().equals("loop")) { - tok.consume(); - expect(Tokenizer.Token.OPEN); - expect(Tokenizer.Token.IDENT); - String var = tok.getIdent(); - expect(Tokenizer.Token.COMMA); - int count = (int) parseInt(); - if (count > 1 << 16) - throw new ParserException(Lang.get("err_toManyTestEntries")); - expect(Tokenizer.Token.CLOSE); - list.add(new LineEmitterRepeat(var, count, parseValues(true))); - } else { - list.add(parseLine()); - } + case NUMBER: + list.add(parseSingleRow()); + break; + case END: + tok.consume(); + expect(Tokenizer.Token.LOOP); + if (!loop) + throw newUnexpectedToken(t); + return list.minimize(); + case REPEAT: + tok.consume(); + expect(Tokenizer.Token.OPEN); + int count = (int) parseInt(); + if (count > 1 << 16) + throw new ParserException(Lang.get("err_toManyTestEntries")); + expect(Tokenizer.Token.CLOSE); + list.add(new LineEmitterRepeat("n", count, parseSingleRow())); + break; + case LOOP: + tok.consume(); + expect(Tokenizer.Token.OPEN); + expect(Tokenizer.Token.IDENT); + String var = tok.getIdent(); + expect(Tokenizer.Token.COMMA); + count = (int) parseInt(); + if (count > 1 << 16) + throw new ParserException(Lang.get("err_toManyTestEntries")); + expect(Tokenizer.Token.CLOSE); + list.add(new LineEmitterRepeat(var, count, parseRows(true))); break; default: throw newUnexpectedToken(t); @@ -121,7 +119,7 @@ public class Parser { } } - private LineEmitter parseLine() throws IOException, ParserException { + private LineEmitter parseSingleRow() throws IOException, ParserException { LineEmitterSimple line = null; while (true) { Tokenizer.Token token = tok.next(); @@ -132,25 +130,24 @@ public class Parser { Value num = new Value(tok.getIdent()); line.add((vals, conext) -> vals.add(num)); break; + case BITS: + expect(Tokenizer.Token.OPEN); + int bitCount = (int) parseInt(); + expect(Tokenizer.Token.COMMA); + Expression exp = parseExpression(); + line.add(new ValueAppenderBits(bitCount, exp)); + expect(Tokenizer.Token.CLOSE); + break; case IDENT: - if (tok.getIdent().equals("bits")) { - expect(Tokenizer.Token.OPEN); - int bitCount = (int) parseInt(); - expect(Tokenizer.Token.COMMA); - Expression exp = parseExpression(); - line.add(new ValueAppenderBits(bitCount, exp)); - expect(Tokenizer.Token.CLOSE); - } else { - try { - final Value value = new Value(tok.getIdent().toUpperCase()); - line.add((vals, context) -> vals.add(value)); - } catch (NumberFormatException e) { - throw new ParserException(Lang.get("err_notANumber_N0_inLine_N1", tok.getIdent(), tok.getLine())); - } + try { + final Value value = new Value(tok.getIdent().toUpperCase()); + line.add((vals, context) -> vals.add(value)); + } catch (NumberFormatException e) { + throw new ParserException(Lang.get("err_notANumber_N0_inLine_N1", tok.getIdent(), tok.getLine())); } break; case OPEN: - Expression exp = parseExpression(); + exp = parseExpression(); line.add((vals, context) -> vals.add(new Value((int) exp.value(context)))); expect(Tokenizer.Token.CLOSE); break; diff --git a/src/main/java/de/neemann/digital/testing/parser/Tokenizer.java b/src/main/java/de/neemann/digital/testing/parser/Tokenizer.java index 8db3ac2dd..382f37d75 100644 --- a/src/main/java/de/neemann/digital/testing/parser/Tokenizer.java +++ b/src/main/java/de/neemann/digital/testing/parser/Tokenizer.java @@ -2,6 +2,7 @@ package de.neemann.digital.testing.parser; import java.io.IOException; import java.io.Reader; +import java.util.HashMap; /** * Simple tokenizer to tokenize boolean expressions. @@ -10,7 +11,19 @@ import java.io.Reader; */ public class Tokenizer { - enum Token {UNKNOWN, IDENT, AND, OR, NOT, OPEN, CLOSE, NUMBER, EOL, EOF, SHIFTLEFT, SHIFTRIGHT, COMMA, EQUAL, ADD, SUB, MUL, GREATER, SMALER, DIV} + enum Token { + UNKNOWN, IDENT, AND, OR, NOT, OPEN, CLOSE, NUMBER, EOL, EOF, SHIFTLEFT, SHIFTRIGHT, COMMA, EQUAL, + ADD, SUB, MUL, GREATER, SMALER, DIV, END, LOOP, REPEAT, BITS + } + + private static HashMap statementMap = new HashMap<>(); + + static { + statementMap.put("end", Token.END); + statementMap.put("loop", Token.LOOP); + statementMap.put("repeat", Token.REPEAT); + statementMap.put("bits", Token.BITS); + } private final Reader in; private Token token; @@ -136,6 +149,8 @@ public class Tokenizer { wasChar = false; } } while (wasChar); + token = statementMap.get(builder.toString()); + if (token == null) token = Token.IDENT; } else if (isNumberChar(c)) { token = Token.NUMBER; builder.setLength(0); diff --git a/src/test/java/de/neemann/digital/testing/parser/ParserLoopTest.java b/src/test/java/de/neemann/digital/testing/parser/ParserLoopTest.java index c2eafbd31..d6e33c32b 100644 --- a/src/test/java/de/neemann/digital/testing/parser/ParserLoopTest.java +++ b/src/test/java/de/neemann/digital/testing/parser/ParserLoopTest.java @@ -37,7 +37,7 @@ public class ParserLoopTest extends TestCase { } public void testNested() throws IOException, ParserException { - Parser parser = new Parser("A B\nloop(i,10)\nloop(j,10)\n C ((i+j)*2)\nend loop\nend loop").parse(); + Parser parser = new Parser("A B\nloop(i,10)\nloop(j,10)\n C (i+j*2)\nend loop\nend loop").parse(); LineCollector td = new LineCollector(parser); assertEquals(2, td.getNames().size()); @@ -47,7 +47,7 @@ public class ParserLoopTest extends TestCase { for (int j = 0; j < 10; j++) { int ind = i * 10 + j; assertEquals(Value.Type.CLOCK, td.getLines().get(ind)[0].getType()); - assertEquals((i + j) * 2, td.getLines().get(ind)[1].getValue()); + assertEquals(i + j * 2, td.getLines().get(ind)[1].getValue()); } } } @@ -69,7 +69,7 @@ public class ParserLoopTest extends TestCase { public void testMissingEndLoop() throws IOException, ParserException { try { - new Parser("A B\nloop(i,10) C ((i+j)*2)").parse(); + new Parser("A B\nloop(i,10) C (i)").parse(); fail(); } catch (ParserException e) { } @@ -77,7 +77,7 @@ public class ParserLoopTest extends TestCase { public void testUnexpectedEndLoop() throws IOException, ParserException { try { - new Parser("A B\n C ((i+j)*2)\nend loop").parse(); + new Parser("A B\n C 1\nend loop").parse(); fail(); } catch (ParserException e) { } @@ -85,7 +85,7 @@ public class ParserLoopTest extends TestCase { public void testIncompleteEndLoop() throws IOException, ParserException { try { - new Parser("A B\n C ((i+j)*2)\nend").parse(); + new Parser("A B\n C 1\nend").parse(); fail(); } catch (ParserException e) { }