diff options
| author | Student <student@Administrators-iMac-2.local> | 2017-04-12 11:05:57 -0400 |
|---|---|---|
| committer | Student <student@Administrators-iMac-2.local> | 2017-04-12 11:05:57 -0400 |
| commit | 22c356cd411cf0fcc18d548291af26bc7588a3aa (patch) | |
| tree | 4f24fdda182b358ca96aed2249bb4e8a19994747 /JPratt/src/main/java/bjc/pratt/PrattParser.java | |
| parent | 2dc1b5dd145ab0e2b3e3df67f967a9c07ed6d303 (diff) | |
| parent | f394306a4b65a3328551f9f6b8d4abff8bfd5b27 (diff) | |
Merge branch 'master' of https://github.com/bculkin2442/JPratt.git
Diffstat (limited to 'JPratt/src/main/java/bjc/pratt/PrattParser.java')
| -rw-r--r-- | JPratt/src/main/java/bjc/pratt/PrattParser.java | 204 |
1 files changed, 140 insertions, 64 deletions
diff --git a/JPratt/src/main/java/bjc/pratt/PrattParser.java b/JPratt/src/main/java/bjc/pratt/PrattParser.java index e08a67c..7783736 100644 --- a/JPratt/src/main/java/bjc/pratt/PrattParser.java +++ b/JPratt/src/main/java/bjc/pratt/PrattParser.java @@ -1,28 +1,34 @@ package bjc.pratt; -import bjc.pratt.commands.DefaultInitialCommand; -import bjc.pratt.commands.DefaultNonInitialCommand; +import java.util.HashMap; +import java.util.Map; + +import bjc.pratt.commands.InitialCommand; +import bjc.pratt.commands.MetaInitialCommand; +import bjc.pratt.commands.MetaNonInitialCommand; +import bjc.pratt.commands.NonInitialCommand; +import bjc.pratt.commands.impls.DefaultInitialCommand; +import bjc.pratt.commands.impls.DefaultNonInitialCommand; +import bjc.pratt.tokens.Token; +import bjc.pratt.tokens.TokenStream; import bjc.utils.data.ITree; import bjc.utils.funcutils.NumberUtils; import bjc.utils.parserutils.ParserException; -import java.util.HashMap; -import java.util.Map; - /** * A configurable Pratt parser for expressions. - * + * * @author EVE - * + * * @param <K> * The key type for the tokens. - * + * * @param <V> * The value type for the tokens. - * + * * @param <C> * The state type of the parser. - * + * * */ public class PrattParser<K, V, C> { @@ -35,94 +41,97 @@ public class PrattParser<K, V, C> { /* * Left-commands that depend on what the null command was. */ - private Map<K, Map<K, NonInitialCommand<K, V, C>>> dependantLeftCommands; - + private final Map<K, Map<K, NonInitialCommand<K, V, C>>> dependantLeftCommands; + private final Map<K, Map<K, MetaNonInitialCommand<K, V, C>>> dependantMetaLeftCommands; /* * The left commands. */ - private Map<K, NonInitialCommand<K, V, C>> leftCommands; + private final Map<K, NonInitialCommand<K, V, C>> leftCommands; + private final Map<K, MetaNonInitialCommand<K, V, C>> metaLeftCommands; + /* * The initial commands. */ - private Map<K, InitialCommand<K, V, C>> nullCommands; + private final Map<K, InitialCommand<K, V, C>> nullCommands; + private final Map<K, MetaInitialCommand<K, V, C>> metaNullCommands; + /* * Initial commands only checked for statements. */ - private Map<K, InitialCommand<K, V, C>> statementCommands; + private final Map<K, InitialCommand<K, V, C>> statementCommands; + private final Map<K, MetaInitialCommand<K, V, C>> metaStatementCommands; /** * Create a new Pratt parser. - * + * */ public PrattParser() { dependantLeftCommands = new HashMap<>(); + dependantMetaLeftCommands = new HashMap<>(); leftCommands = new HashMap<>(); + metaLeftCommands = new HashMap<>(); + nullCommands = new HashMap<>(); + metaNullCommands = new HashMap<>(); + statementCommands = new HashMap<>(); + metaStatementCommands = new HashMap<>(); } /** * Parse an expression. - * + * * @param precedence * The initial precedence for the expression. - * + * * @param tokens * The tokens for the expression. - * + * * @param state * The state of the parser. - * + * * @param isStatement * Whether or not to parse statements. - * + * * @return The expression as an AST. - * + * * @throws ParserException * If something goes wrong during parsing. */ - public ITree<Token<K, V>> parseExpression(int precedence, TokenStream<K, V> tokens, C state, - boolean isStatement) throws ParserException { - if (precedence < 0) { + public ITree<Token<K, V>> parseExpression(final int precedence, final TokenStream<K, V> tokens, final C state, + final boolean isStatement) throws ParserException { + if (precedence < 0) throw new IllegalArgumentException("Precedence must be greater than zero"); - } - Token<K, V> initToken = tokens.current(); + ParserContext<K, V, C> parserContext = new ParserContext<>(tokens, this, state); + + final Token<K, V> initToken = tokens.current(); tokens.next(); - K initKey = initToken.getKey(); + final K initKey = initToken.getKey(); - ITree<Token<K, V>> ast; + InitialCommand<K, V, C> nullCommand = getInitialCommand(isStatement, initKey, parserContext); + ITree<Token<K, V>> ast = nullCommand.denote(initToken, parserContext); - if (isStatement && statementCommands.containsKey(initKey)) { - ast = statementCommands.getOrDefault(initKey, DEFAULT_NULL_COMMAND).denote(initToken, - new ParserContext<>(tokens, this, state)); - } else { - ast = nullCommands.getOrDefault(initKey, DEFAULT_NULL_COMMAND).denote(initToken, - new ParserContext<>(tokens, this, state)); - } + parserContext.initial = initKey; int rightPrec = Integer.MAX_VALUE; while (true) { - Token<K, V> tok = tokens.current(); + final Token<K, V> tok = tokens.current(); - K key = tok.getKey(); + final K key = tok.getKey(); - NonInitialCommand<K, V, C> command = leftCommands.getOrDefault(key, DEFAULT_LEFT_COMMAND); - - if (dependantLeftCommands.containsKey(initKey)) { - command = dependantLeftCommands.get(initKey).getOrDefault(key, command); - } + NonInitialCommand<K, V, C> leftCommand = getNonInitialCommand(key, parserContext); - int leftBind = command.leftBinding(); + final int leftBind = leftCommand.leftBinding(); if (NumberUtils.between(precedence, rightPrec, leftBind)) { tokens.next(); - ast = command.denote(ast, tok, new ParserContext<>(tokens, this, state)); - rightPrec = command.nextBinding(); + ast = leftCommand.denote(ast, tok, parserContext); + rightPrec = leftCommand.nextBinding(); } else { break; } @@ -133,58 +142,125 @@ public class PrattParser<K, V, C> { /** * Add a non-initial command to this parser. - * + * * @param marker * The key that marks the command. - * + * * @param comm * The command. */ - public void addNonInitialCommand(K marker, NonInitialCommand<K, V, C> comm) { + public void addNonInitialCommand(final K marker, final NonInitialCommand<K, V, C> comm) { leftCommands.put(marker, comm); } /** * Add a initial command to this parser. - * + * * @param marker * The key that marks the command. - * + * * @param comm * The command. */ - public void addInitialCommand(K marker, InitialCommand<K, V, C> comm) { + public void addInitialCommand(final K marker, final InitialCommand<K, V, C> comm) { nullCommands.put(marker, comm); } /** * Add a statement command to this parser. - * + * * The difference between statements and initial commands is that * statements can only appear at the start of the expression. - * + * * @param marker * The key that marks the command. - * + * * @param comm * The command. */ - public void addStatementCommand(K marker, InitialCommand<K, V, C> comm) { + public void addStatementCommand(final K marker, final InitialCommand<K, V, C> comm) { statementCommands.put(marker, comm); } /** - * Add a dependant non-initial command to this parser. + * Add a dependent non-initial command to this parser. + * + * @param dependant + * The dependent that precedes the command. + * + * @param marker + * The token key that marks the command. + * + * @param comm + * The command. */ - public void addDependantCommand(K dependant, K marker, NonInitialCommand<K, V, C> comm) { - if (dependantLeftCommands.containsKey(dependant)) { - dependantLeftCommands.get(dependant).put(marker, comm); - } else { - Map<K, NonInitialCommand<K, V, C>> comms = new HashMap<>(); + public void addDependantCommand(final K dependant, final K marker, final NonInitialCommand<K, V, C> comm) { + Map<K, NonInitialCommand<K, V, C>> dependantMap = dependantLeftCommands.getOrDefault(dependant, + new HashMap<>()); - comms.put(marker, comm); + dependantMap.put(marker, comm); + } - dependantLeftCommands.put(dependant, comms); + /** + * Lookup an initial command. + * + * @param isStatement + * Whether to look for statement commands or not. + * + * @param key + * The key of the command. + * + * @param ctx + * The context for meta-commands. + * + * @return A command attached to that key, or a default implementation. + */ + public InitialCommand<K, V, C> getInitialCommand(boolean isStatement, K key, ParserContext<K, V, C> ctx) { + if (isStatement) { + if (metaStatementCommands.containsKey(key)) + return metaStatementCommands.get(key).getCommand(ctx); + else if (statementCommands.containsKey(key)) + return statementCommands.get(key); } + + if (metaNullCommands.containsKey(key)) + return metaNullCommands.get(key).getCommand(ctx); + else + return nullCommands.getOrDefault(key, DEFAULT_NULL_COMMAND); + } + + /** + * Lookup a non-initial command. + * + * @param key + * The key of the command. + * + * @param ctx + * The context for meta-commands. + * + * @return A command attached to that key, or a default implementation. + */ + public NonInitialCommand<K, V, C> getNonInitialCommand(K key, ParserContext<K, V, C> ctx) { + if (dependantMetaLeftCommands.containsKey(ctx.initial)) { + Map<K, MetaNonInitialCommand<K, V, C>> dependantCommands = dependantMetaLeftCommands + .get(ctx.initial); + + if (dependantCommands.containsKey(key)) { + return dependantCommands.get(key).getCommand(ctx); + } + } + + if (dependantLeftCommands.containsKey(ctx.initial)) { + Map<K, NonInitialCommand<K, V, C>> dependantCommands = dependantLeftCommands.get(ctx.initial); + + if (dependantCommands.containsKey(key)) { + return dependantCommands.getOrDefault(key, DEFAULT_LEFT_COMMAND); + } + } + + if (metaLeftCommands.containsKey(key)) { + return metaLeftCommands.get(key).getCommand(ctx); + } else + return leftCommands.getOrDefault(key, DEFAULT_LEFT_COMMAND); } }
\ No newline at end of file |
