From 0f6565687e03968abd2e508fa8183f50f04f1cc7 Mon Sep 17 00:00:00 2001 From: bjculkin Date: Fri, 24 Mar 2017 16:21:07 -0400 Subject: Update Pratt Parser --- .../java/bjc/utils/examples/DelimSplitterTest.java | 10 +-- .../utils/examples/parsing/PrattParserTest.java | 99 ++++++++++++++++------ .../bjc/utils/examples/parsing/TestContext.java | 40 +++++++++ 3 files changed, 120 insertions(+), 29 deletions(-) create mode 100644 BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/TestContext.java (limited to 'BJC-Utils2/src/examples/java/bjc') diff --git a/BJC-Utils2/src/examples/java/bjc/utils/examples/DelimSplitterTest.java b/BJC-Utils2/src/examples/java/bjc/utils/examples/DelimSplitterTest.java index 4262ad2..5f4ef92 100644 --- a/BJC-Utils2/src/examples/java/bjc/utils/examples/DelimSplitterTest.java +++ b/BJC-Utils2/src/examples/java/bjc/utils/examples/DelimSplitterTest.java @@ -2,13 +2,13 @@ package bjc.utils.examples; import bjc.utils.data.ITree; import bjc.utils.funcutils.StringUtils; -import bjc.utils.parserutils.TokenSplitter; import bjc.utils.parserutils.delims.DelimiterException; import bjc.utils.parserutils.delims.DelimiterGroup; import bjc.utils.parserutils.delims.RegexCloser; import bjc.utils.parserutils.delims.RegexOpener; import bjc.utils.parserutils.delims.SequenceDelimiter; import bjc.utils.parserutils.delims.StringDelimiter; +import bjc.utils.parserutils.splitter.SimpleTokenSplitter; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -22,13 +22,13 @@ import java.util.Map; import java.util.Scanner; /** - * Test for {@link SequenceDelimiter} as well as {@link TokenSplitter} + * Test for {@link SequenceDelimiter} as well as {@link SimpleTokenSplitter} * * @author EVE * */ public class DelimSplitterTest { - private TokenSplitter split; + private SimpleTokenSplitter split; private StringDelimiter dlm; @@ -46,7 +46,7 @@ public class DelimSplitterTest { groups = new HashMap<>(); - split = new TokenSplitter(); + split = new SimpleTokenSplitter(); dlm = new StringDelimiter(); @@ -172,7 +172,7 @@ public class DelimSplitterTest { System.out.println(split.toString()); break; case "splitter-reset": - split = new TokenSplitter(); + split = new SimpleTokenSplitter(); if(verbose) { System.out.println("Reset splitter"); } diff --git a/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/PrattParserTest.java b/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/PrattParserTest.java index b4d40b2..3462d74 100644 --- a/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/PrattParserTest.java +++ b/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/PrattParserTest.java @@ -2,12 +2,14 @@ package bjc.utils.examples.parsing; import bjc.utils.data.ITree; import bjc.utils.data.TransformIterator; +import bjc.utils.esodata.Directory; import bjc.utils.parserutils.ParserException; -import bjc.utils.parserutils.TokenSplitter; import bjc.utils.parserutils.pratt.PrattParser; import bjc.utils.parserutils.pratt.StringToken; import bjc.utils.parserutils.pratt.StringTokenStream; import bjc.utils.parserutils.pratt.Token; +import bjc.utils.parserutils.splitter.TokenSplitter; +import bjc.utils.parserutils.splitter.TwoLevelSplitter; import java.util.Arrays; import java.util.HashSet; @@ -17,9 +19,10 @@ import java.util.LinkedList; import java.util.List; import java.util.Scanner; import java.util.Set; +import java.util.function.UnaryOperator; -import static bjc.utils.parserutils.pratt.LeftCommands.*; -import static bjc.utils.parserutils.pratt.NullCommands.*; +import static bjc.utils.parserutils.pratt.commands.NonInitialCommands.*; +import static bjc.utils.parserutils.pratt.commands.InitialCommands.*; /** * Simple test for pratt parser. @@ -28,11 +31,37 @@ import static bjc.utils.parserutils.pratt.NullCommands.*; * */ public class PrattParserTest { + private static final class BlockExit implements UnaryOperator { + @Override + public TestContext apply(TestContext state) { + state.scopes.pop(); + + state.blockCount.pop(); + + return state; + } + } + + private static final class BlockEnter implements UnaryOperator { + @Override + public TestContext apply(TestContext state) { + Directory enclosing = state.scopes.top(); + int currBlockNumber = state.blockCount.pop(); + + state.scopes.push(enclosing.newSubdirectory("block" + currBlockNumber)); + + state.blockCount.push(currBlockNumber + 1); + state.blockCount.push(0); + + return state; + } + } + /** * Main method. * * @param args - * Unused CLI arguments. + * Unused CLI arguments. */ public static void main(String[] args) { /* @@ -45,11 +74,13 @@ public class PrattParserTest { ops.addAll(Arrays.asList("<=", ">=")); ops.add("."); + ops.add(";"); ops.addAll(Arrays.asList("=", "<", ">")); ops.addAll(Arrays.asList("+", "-", "*", "/")); ops.addAll(Arrays.asList("^", "!")); ops.addAll(Arrays.asList("(", ")")); ops.addAll(Arrays.asList("[", "]")); + ops.addAll(Arrays.asList("{", "}")); /* * Reserved words that represent themselves, not literals. @@ -57,23 +88,36 @@ public class PrattParserTest { Set reserved = new LinkedHashSet<>(); reserved.addAll(Arrays.asList("if", "then", "else")); reserved.addAll(Arrays.asList("and", "or")); - - TokenSplitter split = new TokenSplitter(); - ops.forEach(split::addDelimiter); + reserved.addAll(Arrays.asList("begin", "end")); + + TwoLevelSplitter split = new TwoLevelSplitter(); + + split.addCompoundDelim(":="); + split.addCompoundDelim("||", "&&"); + split.addCompoundDelim("<=", ">="); - split.addNonMatcher("<=", ">="); + split.addSimpleDelim("."); + split.addSimpleDelim(";"); + split.addSimpleDelim("=", "<", ">"); + split.addSimpleDelim("+", "-", "*", "/"); + split.addSimpleDelim("^", "!"); + split.addSimpleMulti("\\(", "\\)"); + split.addSimpleMulti("\\[", "\\]"); + split.addSimpleMulti("\\{", "\\}"); split.compile(); - PrattParser parser = createParser(); + PrattParser parser = createParser(); + + TestContext ctx = new TestContext(); Scanner scn = new Scanner(System.in); System.out.print("Enter a command (blank line to exit): "); String ln = scn.nextLine(); - while (!ln.trim().equals("")) { - Iterator> tokens = preprocessInput(ops, split, ln, reserved); + while(!ln.trim().equals("")) { + Iterator> tokens = preprocessInput(ops, split, ln, reserved, ctx); try { StringTokenStream tokenStream = new StringTokenStream(tokens); @@ -83,14 +127,14 @@ public class PrattParserTest { */ tokenStream.next(); - ITree> tree = parser.parseExpression(0, tokenStream, null, true); + ITree> tree = parser.parseExpression(0, tokenStream, ctx, true); - if (!tokenStream.current().getKey().equals("(end)")) { + if(!tokenStream.current().getKey().equals("(end)")) { System.out.println("Multipe expressions on line"); } System.out.println("Parsed expression:\n" + tree); - } catch (ParserException pex) { + } catch(ParserException pex) { pex.printStackTrace(); } @@ -98,16 +142,19 @@ public class PrattParserTest { ln = scn.nextLine(); } + System.out.println(); + System.out.println("Context is:\n" + ctx); + scn.close(); } private static Iterator> preprocessInput(Set ops, TokenSplitter split, String ln, - Set reserved) { + Set reserved, TestContext ctx) { String[] rawTokens = ln.split("\\s+"); List splitTokens = new LinkedList<>(); - for (String raw : rawTokens) { + for(String raw : rawTokens) { String[] strangs = split.split(raw); splitTokens.addAll(Arrays.asList(strangs)); @@ -118,7 +165,7 @@ public class PrattParserTest { Iterator source = splitTokens.iterator(); Iterator> tokens = new TransformIterator<>(source, (String strang) -> { - if (ops.contains(strang) || reserved.contains(strang)) { + if(ops.contains(strang) || reserved.contains(strang)) { return new StringToken(strang, strang); } else { return new StringToken("(literal)", strang); @@ -127,7 +174,7 @@ public class PrattParserTest { return tokens; } - private static PrattParser createParser() { + private static PrattParser createParser() { /* * Set of which relational operators chain with each other. */ @@ -139,7 +186,7 @@ public class PrattParserTest { */ StringToken chainToken = new StringToken("and", "and"); - PrattParser parser = new PrattParser<>(); + PrattParser parser = new PrattParser<>(); parser.addNonInitialCommand("if", ternary(5, 0, "else", new StringToken("cond", "cond"), false)); @@ -147,7 +194,7 @@ public class PrattParserTest { parser.addNonInitialCommand("and", infixLeft(13)); parser.addNonInitialCommand("or", infixLeft(13)); - + parser.addNonInitialCommand("=", chain(15, relChain, chainToken)); parser.addNonInitialCommand("<", chain(15, relChain, chainToken)); parser.addNonInitialCommand(">", chain(15, relChain, chainToken)); @@ -156,7 +203,7 @@ public class PrattParserTest { parser.addNonInitialCommand("&&", infixRight(17)); parser.addNonInitialCommand("||", infixRight(17)); - + parser.addNonInitialCommand("+", infixLeft(20)); parser.addNonInitialCommand("-", infixLeft(20)); @@ -168,12 +215,16 @@ public class PrattParserTest { parser.addNonInitialCommand("^", infixRight(50)); parser.addNonInitialCommand(".", infixLeft(60)); - + parser.addNonInitialCommand("[", postCircumfix(60, 0, "]", new StringToken("idx", "idx"))); - parser.addInitialCommand("if", preTernary(0, 0, 0, "then", "else", new StringToken("ifelse", "ifelse"))); + parser.addInitialCommand("if", + preTernary(0, 0, 0, "then", "else", new StringToken("ifelse", "ifelse"))); + + parser.addInitialCommand("(", grouping(0, ")", new StringToken("parens", "parens"))); - parser.addInitialCommand("(", grouping(0, ")", new StringToken("()", "()"))); + parser.addInitialCommand("{", delimited(0, ";", "}", new StringToken("block", "block"), + new BlockEnter(), (state) -> state, new BlockExit(), true)); parser.addInitialCommand("-", unary(30)); diff --git a/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/TestContext.java b/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/TestContext.java new file mode 100644 index 0000000..cc1be17 --- /dev/null +++ b/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/TestContext.java @@ -0,0 +1,40 @@ +package bjc.utils.examples.parsing; + +import bjc.utils.esodata.Directory; +import bjc.utils.esodata.SimpleDirectory; +import bjc.utils.esodata.SimpleStack; +import bjc.utils.esodata.Stack; + +/** + * Simple context for the parser. + * + * @author EVE + * + */ +public class TestContext { + /** + * The variable scoping information. + */ + public Stack> scopes; + + /** + * The current number of scopes inside this scope. + */ + public Stack blockCount; + + /** + * Create a new test context. + */ + public TestContext() { + scopes = new SimpleStack<>(); + blockCount = new SimpleStack<>(); + + scopes.push(new SimpleDirectory<>()); + blockCount.push(0); + } + + @Override + public String toString() { + return String.format("TestContext [scopes=%s, blockCount=%s]", scopes, blockCount); + } +} -- cgit v1.2.3