diff options
Diffstat (limited to 'BJC-Utils2')
4 files changed, 167 insertions, 50 deletions
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 8634641..b4d40b2 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 @@ -32,7 +32,7 @@ public class PrattParserTest { * Main method. * * @param args - * Unused CLI arguments. + * Unused CLI arguments. */ public static void main(String[] args) { /* @@ -41,8 +41,10 @@ public class PrattParserTest { Set<String> ops = new LinkedHashSet<>(); ops.add(":="); + ops.addAll(Arrays.asList("||", "&&")); ops.addAll(Arrays.asList("<=", ">=")); + ops.add("."); ops.addAll(Arrays.asList("=", "<", ">")); ops.addAll(Arrays.asList("+", "-", "*", "/")); ops.addAll(Arrays.asList("^", "!")); @@ -53,9 +55,9 @@ public class PrattParserTest { * Reserved words that represent themselves, not literals. */ Set<String> reserved = new LinkedHashSet<>(); - reserved.add("if"); - reserved.add("else"); - + reserved.addAll(Arrays.asList("if", "then", "else")); + reserved.addAll(Arrays.asList("and", "or")); + TokenSplitter split = new TokenSplitter(); ops.forEach(split::addDelimiter); @@ -81,7 +83,7 @@ public class PrattParserTest { */ tokenStream.next(); - ITree<Token<String, String>> tree = parser.parseExpression(0, tokenStream, null); + ITree<Token<String, String>> tree = parser.parseExpression(0, tokenStream, null, true); if (!tokenStream.current().getKey().equals("(end)")) { System.out.println("Multipe expressions on line"); @@ -129,8 +131,8 @@ public class PrattParserTest { /* * Set of which relational operators chain with each other. */ - HashSet<String> chainSet = new HashSet<>(); - chainSet.addAll(Arrays.asList("=", "<", ">", "<=", ">=")); + HashSet<String> relChain = new HashSet<>(); + relChain.addAll(Arrays.asList("=", "<", ">", "<=", ">=")); /* * Token for marking chains. @@ -143,12 +145,18 @@ public class PrattParserTest { parser.addNonInitialCommand(":=", infixNon(10)); - parser.addNonInitialCommand("=", chain(10, chainSet, chainToken)); - parser.addNonInitialCommand("<", chain(10, chainSet, chainToken)); - parser.addNonInitialCommand(">", chain(10, chainSet, chainToken)); - parser.addNonInitialCommand("<=", chain(10, chainSet, chainToken)); - parser.addNonInitialCommand(">=", chain(10, chainSet, chainToken)); - + 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)); + parser.addNonInitialCommand("<=", chain(15, relChain, chainToken)); + parser.addNonInitialCommand(">=", chain(15, relChain, chainToken)); + + parser.addNonInitialCommand("&&", infixRight(17)); + parser.addNonInitialCommand("||", infixRight(17)); + parser.addNonInitialCommand("+", infixLeft(20)); parser.addNonInitialCommand("-", infixLeft(20)); @@ -159,10 +167,18 @@ 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("(", grouping(0, ")", new StringToken("()", "()"))); + + parser.addInitialCommand("-", unary(30)); + parser.addInitialCommand("(literal)", leaf()); + return parser; } } diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/LeftCommands.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/LeftCommands.java index 5844c49..82ec843 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/LeftCommands.java +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/LeftCommands.java @@ -40,7 +40,7 @@ public class LeftCommands { @Override public ITree<Token<K, V>> leftDenote(ITree<Token<K, V>> operand, Token<K, V> operator, ParserContext<K, V, C> ctx) throws ParserException { - ITree<Token<K, V>> opr = ctx.parse.parseExpression(rightBinding(), ctx.tokens, ctx.state); + ITree<Token<K, V>> opr = ctx.parse.parseExpression(rightBinding(), ctx.tokens, ctx.state, false); return new Tree<>(operator, operand, opr); } @@ -101,7 +101,7 @@ public class LeftCommands { @Override public ITree<Token<K, V>> leftDenote(ITree<Token<K, V>> operand, Token<K, V> operator, ParserContext<K, V, C> ctx) throws ParserException { - ITree<Token<K, V>> inside = ctx.parse.parseExpression(insidePrec, ctx.tokens, ctx.state); + ITree<Token<K, V>> inside = ctx.parse.parseExpression(insidePrec, ctx.tokens, ctx.state, false); ctx.tokens.expect(term); @@ -142,11 +142,11 @@ public class LeftCommands { @Override public ITree<Token<K, V>> leftDenote(ITree<Token<K, V>> operand, Token<K, V> operator, ParserContext<K, V, C> ctx) throws ParserException { - ITree<Token<K, V>> inner = ctx.parse.parseExpression(innerExp, ctx.tokens, ctx.state); + ITree<Token<K, V>> inner = ctx.parse.parseExpression(innerExp, ctx.tokens, ctx.state, false); ctx.tokens.expect(term); - ITree<Token<K, V>> outer = ctx.parse.parseExpression(1 + leftBinding(), ctx.tokens, ctx.state); + ITree<Token<K, V>> outer = ctx.parse.parseExpression(1 + leftBinding(), ctx.tokens, ctx.state, false); return new Tree<>(mark, inner, operand, outer); } @@ -176,7 +176,7 @@ public class LeftCommands { @Override public ITree<Token<K, V>> leftDenote(ITree<Token<K, V>> operand, Token<K, V> operator, ParserContext<K, V, C> ctx) throws ParserException { - ITree<Token<K, V>> tree = ctx.parse.parseExpression(1 + leftBinding(), ctx.tokens, ctx.state); + ITree<Token<K, V>> tree = ctx.parse.parseExpression(1 + leftBinding(), ctx.tokens, ctx.state, false); ITree<Token<K, V>> res = new Tree<>(operator, operand, tree); diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/NullCommands.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/NullCommands.java index cf57241..f0c2a80 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/NullCommands.java +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/NullCommands.java @@ -16,7 +16,7 @@ public class NullCommands { @Override public ITree<Token<K, V>> nullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx) throws ParserException { - //tokens.next(); + // tokens.next(); return intNullDenotation(operator, ctx); } @@ -36,16 +36,16 @@ public class NullCommands { @Override protected ITree<Token<K, V>> intNullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx) throws ParserException { - ITree<Token<K, V>> opr = ctx.parse.parseExpression(nullPwer, ctx.tokens, ctx.state); + ITree<Token<K, V>> opr = ctx.parse.parseExpression(nullPwer, ctx.tokens, ctx.state, false); return new Tree<>(operator, opr); } } private static class GroupingCommand<K, V, C> extends AbstractNullCommand<K, V, C> { - private K term; - private Token<K, V> mark; - private int inner; + private K term; + private Token<K, V> mark; + private int inner; public GroupingCommand(int innerPrec, K terminator, Token<K, V> marker) { inner = innerPrec; @@ -57,7 +57,7 @@ public class NullCommands { @Override protected ITree<Token<K, V>> intNullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx) throws ParserException { - ITree<Token<K, V>> opr = ctx.parse.parseExpression(inner, ctx.tokens, ctx.state); + ITree<Token<K, V>> opr = ctx.parse.parseExpression(inner, ctx.tokens, ctx.state, false); ctx.tokens.expect(term); @@ -74,11 +74,63 @@ public class NullCommands { } } + private static class ConstantCommand<K, V, C> extends NullCommand<K, V, C> { + private ITree<Token<K, V>> val; + + public ConstantCommand(ITree<Token<K, V>> con) { + val = con; + } + + @Override + public ITree<Token<K, V>> nullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx) + throws ParserException { + return val; + } + } + + private static class PreTernaryCommand<K, V, C> extends AbstractNullCommand<K, V, C> { + private int cond1; + private int block1; + private int block2; + + private K mark1; + private K mark2; + + private Token<K, V> term; + + public PreTernaryCommand(int cond1, int block1, int block2, K mark1, K mark2, Token<K, V> term) { + super(); + this.cond1 = cond1; + this.block1 = block1; + this.block2 = block2; + this.mark1 = mark1; + this.mark2 = mark2; + this.term = term; + } + + @SuppressWarnings("unchecked") + @Override + protected ITree<Token<K, V>> intNullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx) + throws ParserException { + ITree<Token<K, V>> cond = ctx.parse.parseExpression(cond1, ctx.tokens, ctx.state, false); + + ctx.tokens.expect(mark1); + + ITree<Token<K, V>> fstBlock = ctx.parse.parseExpression(block1, ctx.tokens, ctx.state, false); + + ctx.tokens.expect(mark2); + + ITree<Token<K, V>> sndBlock = ctx.parse.parseExpression(block2, ctx.tokens, ctx.state, false); + + return new Tree<>(term, cond, fstBlock, sndBlock); + } + } + /** * Create a new unary operator. * * @param precedence - * The precedence of the operator. + * The precedence of the operator. * * @return A command implementing that operator. */ @@ -90,13 +142,13 @@ public class NullCommands { * Create a new grouping operator. * * @param precedence - * The precedence of the expression in the operator. + * The precedence of the expression in the operator. * * @param term - * The type that closes the group. + * The type that closes the group. * * @param mark - * The token for the AST node of the group. + * The token for the AST node of the group. * * @return A command implementing the operator. */ @@ -112,4 +164,44 @@ public class NullCommands { public static <K, V, C> NullCommand<K, V, C> leaf() { return new LeafCommand<>(); } + + /** + * Create a new pre-ternary operator, like an if-then-else statement. + * + * @param cond1 + * The priority of the first block. + * + * @param block1 + * The priority of the second block. + * + * @param block2 + * The priority of the third block. + * + * @param mark1 + * The marker that ends the first block. + * + * @param mark2 + * The marker that ends the second block. + * + * @param term + * The token for the AST node of the group. + * + * @return A command implementing the operator. + */ + public static <K, V, C> NullCommand<K, V, C> preTernary(int cond1, int block1, int block2, K mark1, K mark2, + Token<K, V> term) { + return new PreTernaryCommand<>(cond1, block1, block2, mark1, mark2, term); + } + + /** + * Create a new named constant. + * + * @param val + * The value of the constant. + * + * @return A command implementing the constant. + */ + public static <K, V, C> NullCommand<K, V, C> constant(ITree<Token<K, V>> val) { + return new ConstantCommand<>(val); + } } diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/PrattParser.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/PrattParser.java index a2cefda..a8c273d 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/PrattParser.java +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/PrattParser.java @@ -13,66 +13,75 @@ import java.util.Map; * @author EVE * * @param <K> - * The key type for the tokens. + * The key type for the tokens. * * @param <V> - * The value type for the tokens. + * The value type for the tokens. * * @param <C> - * The state type of the parser. + * The state type of the parser. * * */ public class PrattParser<K, V, C> { - private final LeftCommand<K, V, C> DEFAULT_LEFT_COMMAND = new DefaultLeftCommand<>(); - private final NullCommand<K, V, C> DEFAULT_NULL_COMMAND = new DefaultNullCommand<>(); + private final LeftCommand<K, V, C> DEFAULT_LEFT_COMMAND = new DefaultLeftCommand<>(); + private final NullCommand<K, V, C> DEFAULT_NULL_COMMAND = new DefaultNullCommand<>(); - private Map<K, LeftCommand<K, V, C>> leftCommands; - private Map<K, NullCommand<K, V, C>> nullCommands; + private Map<K, LeftCommand<K, V, C>> leftCommands; + private Map<K, NullCommand<K, V, C>> nullCommands; + private Map<K, NullCommand<K, V, C>> statementCommands; /** * Create a new Pratt parser. * * @param terminal - * The terminal symbol. + * The terminal symbol. */ public PrattParser() { leftCommands = new HashMap<>(); nullCommands = new HashMap<>(); + statementCommands = new HashMap<>(); } /** * Parse an expression. * * @param precedence - * The initial precedence for the expression. + * The initial precedence for the expression. * * @param tokens - * The tokens for the expression. + * The tokens for the expression. * * @param state - * The state of the parser. + * The state of the parser. * * @return The expression as an AST. * * @throws ParserException - * If something goes wrong during parsing. + * If something goes wrong during parsing. */ - public ITree<Token<K, V>> parseExpression(int precedence, TokenStream<K, V> tokens, C state) + public ITree<Token<K, V>> parseExpression(int precedence, TokenStream<K, V> tokens, C state, boolean isStatement) throws ParserException { - if(precedence < 0) { + if (precedence < 0) { throw new IllegalArgumentException("Precedence must be greater than zero"); } Token<K, V> initToken = tokens.current(); tokens.next(); - ITree<Token<K, V>> ast = nullCommands.getOrDefault(initToken.getKey(), DEFAULT_NULL_COMMAND) - .nullDenotation(initToken, new ParserContext<>(tokens, this, state)); + ITree<Token<K, V>> ast; + + if (isStatement && statementCommands.containsKey(initToken.getKey())) { + ast = statementCommands.getOrDefault(initToken.getKey(), DEFAULT_NULL_COMMAND).nullDenotation(initToken, + new ParserContext<>(tokens, this, state)); + } else { + ast = nullCommands.getOrDefault(initToken.getKey(), DEFAULT_NULL_COMMAND).nullDenotation(initToken, + new ParserContext<>(tokens, this, state)); + } int rightPrec = Integer.MAX_VALUE; - while(true) { + while (true) { Token<K, V> tok = tokens.current(); K key = tok.getKey(); @@ -80,7 +89,7 @@ public class PrattParser<K, V, C> { LeftCommand<K, V, C> command = leftCommands.getOrDefault(key, DEFAULT_LEFT_COMMAND); int leftBind = command.leftBinding(); - if(NumberUtils.between(precedence, rightPrec, leftBind)) { + if (NumberUtils.between(precedence, rightPrec, leftBind)) { tokens.next(); ast = command.leftDenote(ast, tok, new ParserContext<>(tokens, this, state)); @@ -97,10 +106,10 @@ public class PrattParser<K, V, C> { * Add a non-initial command to this parser. * * @param marker - * The key that marks the command. + * The key that marks the command. * * @param comm - * The command. + * The command. */ public void addNonInitialCommand(K marker, LeftCommand<K, V, C> comm) { leftCommands.put(marker, comm); @@ -110,10 +119,10 @@ public class PrattParser<K, V, C> { * Add a initial command to this parser. * * @param marker - * The key that marks the command. + * The key that marks the command. * * @param comm - * The command. + * The command. */ public void addInitialCommand(K marker, NullCommand<K, V, C> comm) { nullCommands.put(marker, comm); |
