diff options
Diffstat (limited to 'RGens/src/main')
3 files changed, 206 insertions, 108 deletions
diff --git a/RGens/src/main/java/bjc/rgens/newparser/GrammarException.java b/RGens/src/main/java/bjc/rgens/newparser/GrammarException.java new file mode 100644 index 0000000..c9f2723 --- /dev/null +++ b/RGens/src/main/java/bjc/rgens/newparser/GrammarException.java @@ -0,0 +1,39 @@ +package bjc.rgens.newparser; + +/** + * The exception thrown when something goes wrong while parsing a + * grammar. + * + * @author student + * + */ +public class GrammarException extends RuntimeException { + /* + * Serialization ID. + */ + private static final long serialVersionUID = -7287427479316953668L; + + /** + * Create a new grammar exception with the specified message. + * + * @param msg + * The message for this exception. + */ + public GrammarException(String msg) { + super(msg); + } + + /** + * Create a new grammar exception with the specified message and + * cause. + * + * @param msg + * The message for this exception. + * + * @param cause + * The cause of this exception. + */ + public GrammarException(String msg, Exception cause) { + super(msg, cause); + } +}
\ No newline at end of file diff --git a/RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java b/RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java index 073e0ee..fdf2433 100644 --- a/RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java +++ b/RGens/src/main/java/bjc/rgens/newparser/RGrammarBuilder.java @@ -29,4 +29,23 @@ public class RGrammarBuilder { */ return null; } + + public void addCasePart(String csepart) { + // TODO Auto-generated method stub + } + + public void endRule() { + // TODO Auto-generated method stub + + } + + public void finishCase() { + // TODO Auto-generated method stub + + } + + public void startWhereBlock(String string) { + // TODO Auto-generated method stub + + } } diff --git a/RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java b/RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java index cf85cb5..9e55736 100644 --- a/RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java +++ b/RGens/src/main/java/bjc/rgens/newparser/RGrammarParser.java @@ -1,6 +1,8 @@ package bjc.rgens.newparser; import bjc.utils.funcutils.TriConsumer; +import bjc.utils.parserutils.BlockReader; +import bjc.utils.parserutils.BlockReader.Block; import java.io.InputStream; import java.io.InputStreamReader; @@ -17,43 +19,16 @@ import java.util.Scanner; * */ public class RGrammarParser { - /** - * The exception thrown when something goes wrong while parsing a - * grammar. - * - * @author student - * + /* + * Templates for level-dependent delimiters. */ - public static class GrammarException extends Exception { - /* - * Serialization ID. - */ - private static final long serialVersionUID = -7287427479316953668L; - - /** - * Create a new grammar exception with the specified message. - * - * @param msg - * The message for this exception. - */ - public GrammarException(String msg) { - super(msg); - } + private static final String TMPL_PRAGMA_BLOCK_DELIM = "\\n\\t{%d}(?!\\t)"; + private static final String TMPL_RULEDECL_BLOCK_DELIM = "\\n\\t\\t{%d}"; - /** - * Create a new grammar exception with the specified message and - * cause. - * - * @param msg - * The message for this exception. - * - * @param cause - * The cause of this exception. - */ - public GrammarException(String msg, Exception cause) { - super(msg, cause); - } - } + /* + * Templates for non-level-dependent delimiters. + */ + private static final String TOPLEVEL_BLOCK_DELIM = "\\n\\.?\\n"; /* * Pragma impls. @@ -79,25 +54,25 @@ public class RGrammarParser { * Thrown if the grammar has a syntax error. */ public RGrammar readGrammar(InputStream is) throws GrammarException { - LineNumberReader lnReader = new LineNumberReader(new InputStreamReader(is)); - - int blockNo = 0; - try(Scanner scn = new Scanner(lnReader)) { - scn.useDelimiter("\\n\\.?\\n"); + try(BlockReader reader = new BlockReader(TOPLEVEL_BLOCK_DELIM, new InputStreamReader(is))) { + if(!reader.hasNextBlock()) { + throw new GrammarException("At least one top-level block must be present"); + } - RGrammarBuilder build = new RGrammarBuilder(); + try { + RGrammarBuilder build = new RGrammarBuilder(); - while(scn.hasNext()) { - String block = scn.next(); - blockNo += 1; + reader.forEachBlock((block) -> { + handleBlock(build, block.contents, 0); + }); - handleBlock(build, block, 0); + return build.toRGrammar(); + } catch(GrammarException gex) { + throw new GrammarException(String.format("Error in block (%s)", reader.getBlock()), + gex); } - - return build.toRGrammar(); - } catch(GrammarException gex) { - throw new GrammarException(String.format("Error in block %d at line %d of stream", blockNo, - lnReader.getLineNumber()), gex); + } catch(Exception ex) { + throw new GrammarException(String.format("Unknown error handling block"), ex); } } @@ -110,14 +85,23 @@ public class RGrammarParser { * Handles an arbitrary block. */ private void handleBlock(RGrammarBuilder build, String block, int level) throws GrammarException { - if(block.startsWith("pragma")) { + int typeSep = block.indexOf(' '); + + if(typeSep == -1) { + throw new GrammarException( + "A block must start with a type, followed by a space, then the rest of the block"); + } + + String blockType = block.substring(0, typeSep); + + if(blockType.equalsIgnoreCase("pragma")) { handlePragmaBlock(block, build, level); - } else if(block.startsWith("[")) { + } else if(blockType.startsWith("[")) { handleRuleBlock(block, build, level); - } else if(block.startsWith("where")) { + } else if(blockType.equalsIgnoreCase("where")) { handleWhereBlock(block, build, level); } else { - throw new GrammarException(String.format("Unknown block: %s", block)); + throw new GrammarException(String.format("Unknown block type: '%s'", blockType)); } } @@ -125,88 +109,144 @@ public class RGrammarParser { * Handle reading a block of pragmas. */ private void handlePragmaBlock(String block, RGrammarBuilder build, int level) throws GrammarException { - LineNumberReader lnReader = new LineNumberReader(new StringReader(block)); - - int pragmaNo = 0; - try(Scanner deblocker = new Scanner(lnReader)) { - deblocker.useDelimiter(String.format("\\n\\t{%d}(?!\\t)", level)); - - while(deblocker.hasNext()) { - String pragma = deblocker.next(); - pragmaNo += 1; - - if(!pragma.startsWith("pragma")) { - throw new GrammarException(String.format("Illegal line: %s", pragma)); - } else { - handlePragma(pragma.substring(7), build, level); - } + try(BlockReader pragmaReader = new BlockReader(String.format(TMPL_PRAGMA_BLOCK_DELIM, level), + new StringReader(block))) { + try { + pragmaReader.forEachBlock((pragma) -> { + String pragmaContents = pragma.contents; + + int pragmaSep = pragmaContents.indexOf(' '); + + if(pragmaSep == -1) { + throw new GrammarException( + "A pragma invocation must consist of the word pragma," + + " followed by a space, then the body of the pragma"); + } + + String pragmaLeader = pragmaContents.substring(0, pragmaSep); + String pragmaBody = pragmaContents.substring(pragmaSep); + + if(!pragmaLeader.equalsIgnoreCase("pragma")) { + throw new GrammarException( + String.format("Illegal line leader in pragma block: '%s'", + pragmaLeader)); + } else { + handlePragma(pragmaBody, build, level); + } + }); + } catch(GrammarException gex) { + Block pragma = pragmaReader.getBlock(); + + throw new GrammarException(String.format("Error in pragma: (%s)", pragma), gex); } - } catch(GrammarException gex) { - throw new GrammarException(String.format("Error in pragma %d at line %d", pragmaNo, - lnReader.getLineNumber()), gex); + } catch(Exception ex) { + throw new GrammarException("Unknown error handling pragma block", ex); } } + /* + * Handle an individual pragma in a block. + */ private void handlePragma(String pragma, RGrammarBuilder build, int level) throws GrammarException { - String pragmaName = pragma.substring(0, pragma.indexOf(' ')); + int bodySep = pragma.indexOf(' '); + + if(bodySep == -1) bodySep = pragma.length(); + + String pragmaName = pragma.substring(0, bodySep); + String pragmaBody = pragma.substring(bodySep); if(pragmas.containsKey(pragmaName)) { - pragmas.get(pragmaName).accept(pragma.substring(pragma.indexOf(' ')), build, level); + pragmas.get(pragmaName).accept(pragmaBody, build, level); } else { - throw new GrammarException(String.format("Unknown pragma %s", pragmaName)); + throw new GrammarException(String.format("Unknown pragma named '%s'", pragmaName)); } } /* - * Handle a block of a rule and multiple cases. + * Handle a block of a rule declaration and one or more cases. */ - private void handleRuleBlock(String block, RGrammarBuilder build, int level) throws GrammarException { - LineNumberReader lnReader = new LineNumberReader(new StringReader(block)); - - int caseNo = 0; - try(Scanner scn = new Scanner(lnReader)) { - scn.useDelimiter(String.format("\\n\\t\\t{%d}", level)); - - String decl = scn.next(); - - String ruleName = decl.substring(0, decl.indexOf(' ')); - - if(ruleName.equals("")) { - throw new GrammarException("The empty string is not a valid rule name"); + private void handleRuleBlock(String ruleBlock, RGrammarBuilder build, int level) throws GrammarException { + try(BlockReader ruleReader = new BlockReader(String.format(TMPL_RULEDECL_BLOCK_DELIM, level), + new StringReader(ruleBlock))) { + try { + if(ruleReader.hasNextBlock()) { + /* + * Rule with a declaration followed by + * multiple cases. + */ + ruleReader.nextBlock(); + Block declBlock = ruleReader.getBlock(); + + String declContents = declBlock.contents; + handleRuleDecl(build, declContents); + + ruleReader.forEachBlock((block) -> { + handleRuleCase(block.contents, build); + }); + } else { + /* + * Rule with a declaration followed by a + * single case. + */ + handleRuleDecl(build, ruleBlock); + } + } catch(GrammarException gex) { + throw new GrammarException( + String.format("Error in rule case (%s)", ruleReader.getBlock()), gex); } + } catch(Exception ex) { + throw new GrammarException("Unknown error handling rule block", ex); + } + } - build.setCurrentRule(ruleName); - - String initCase = decl.substring(decl.indexOf(' ')); - caseNo += 1; + /* + * Handle a rule declaration and its initial case. + */ + private void handleRuleDecl(RGrammarBuilder build, String declContents) { + int declSep = declContents.indexOf("\u2192"); - handleRuleCase(initCase, build); + if(declSep == -1) { + throw new GrammarException("A rule must be given at least one case in its declaration, and" + + "seperated from that case by \u2192"); + } - while(scn.hasNext()) { - String cse = scn.next(); - caseNo += 1; + String ruleName = declContents.substring(0, declSep).trim(); + String ruleBody = declContents.substring(declSep).trim(); - handleRuleCase(cse, build); - } - } catch(GrammarException gex) { - throw new GrammarException( - String.format("Error in case %d at line %d", caseNo, lnReader.getLineNumber()), - gex); + if(ruleName.equals("")) { + throw new GrammarException("The empty string is not a valid rule name"); } + + build.setCurrentRule(ruleName); + + handleRuleCase(ruleBody, build); } /* * Handle a single case of a rule. */ - private void handleRuleCase(String initCase, RGrammarBuilder build) { - // TODO Auto-generated method stub + private void handleRuleCase(String cse, RGrammarBuilder build) { + for(String csepart : cse.split(" ")) { + build.addCasePart(csepart); + } + build.finishCase(); } /* - * Handle a block of a rule with local rules. + * Handle a where block (a block with local rules). */ - private void handleWhereBlock(String block, RGrammarBuilder build, int level) { - // TODO Auto-generated method stub + private void handleWhereBlock(String block, RGrammarBuilder build, int level) throws GrammarException { + try(BlockReader whereReader = new BlockReader("", new StringReader(block))) { + try { + + } catch(GrammarException gex) { + throw new GrammarException( + String.format("Error in where block (%s)", whereReader.getBlock()), + gex); + } + } catch(Exception ex) { + throw new GrammarException("Unknown error in where block", ex); + } } } |
