diff --git a/Source/Parsing/src/ca/uqac/lif/bullwinkle/BnfParser.java b/Source/Parsing/src/ca/uqac/lif/bullwinkle/BnfParser.java index 76e701f..51d5b52 100644 --- a/Source/Parsing/src/ca/uqac/lif/bullwinkle/BnfParser.java +++ b/Source/Parsing/src/ca/uqac/lif/bullwinkle/BnfParser.java @@ -175,14 +175,38 @@ public ParseNode getParseTree(final String input) throws ParseException return null; } + /** + * Adds a rule to the parser. If a rule with the same left-hand side + * already exists in the parser, the case of the rule passed as an argument + * will be added to the cases of the existing rule. + * @param rule The rule to add + */ public void addRule(final BnfRule rule) { + NonTerminalToken r_left = rule.getLeftHandSide(); + for (BnfRule in_rule : m_rules) + { + NonTerminalToken in_left = in_rule.getLeftHandSide(); + if (r_left.equals(in_left)) + { + in_rule.addAlternatives(rule.getAlternatives()); + break; + } + } + // No rule with the same LHS was found m_rules.add(rule); } + /** + * Adds a collection of rules to the parser + * @param rules The rules to add + */ public void addRules(final Collection rules) { - m_rules.addAll(rules); + for (BnfRule rule : rules) + { + addRule(rule); + } } public void setStartRule(final String tokenName) @@ -338,12 +362,12 @@ public void setStartRule(final NonTerminalToken token) return null; } input.truncateSubstring(chars_consumed); - /*if (level == 0 && !input.isEmpty()) + if (level == 0 && !input.isEmpty()) { // The top-level rule must parse the complete string log("FAILED: The top-level rule must parse the complete string", level); return null; - }*/ + } return out_node; } diff --git a/Source/Parsing/src/ca/uqac/lif/bullwinkle/BnfRule.java b/Source/Parsing/src/ca/uqac/lif/bullwinkle/BnfRule.java index 1566479..8970ef6 100644 --- a/Source/Parsing/src/ca/uqac/lif/bullwinkle/BnfRule.java +++ b/Source/Parsing/src/ca/uqac/lif/bullwinkle/BnfRule.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.io.StringReader; +import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -27,18 +28,39 @@ import ca.uqac.lif.util.EmptyException; +/** + * Implementation of a single rule of a BNF grammar + */ public class BnfRule { + /** + * A list of token strings that for all the possible cases of that rule + */ private List m_alternatives; + /** + * The left-hand side of the rule. Since we deal with BNF grammars, this + * left-hand side must be a single non-terminal symbol. + */ private NonTerminalToken m_leftHandSide; + /** + * Creates a new empty BNF rule + */ BnfRule() { super(); m_alternatives = new LinkedList(); } + /** + * Creates a BNF rule out of a string + * @param input The string that contains a BNF rule. This string must follow + * the syntactical restrictions described in the README + * @return A BNF rule if the parsing succeeded + * @throws BnfRule.InvalidRuleException Thrown if the parsing could not be + * done correctly + */ public static BnfRule parseRule(String input) throws BnfRule.InvalidRuleException { // TODO: split parsing of LHS and RHS in two methods. Then, use RHS parsing @@ -119,21 +141,39 @@ else if (trimmed_word.compareTo("\uCEB5") == 0 || trimmed_word.compareTo("\u03B5 return out; } + /** + * Sets the left-hand side of the rule + * @param t The non-terminal token that will be used for the + * left-hand side of the rule + */ void setLeftHandSide(final NonTerminalToken t) { m_leftHandSide = t; } + /** + * Adds an alternative to the rule + * @param ts The alternative to add + */ void addAlternative(/* @NonNull */ final TokenString ts) { m_alternatives.add(ts); } + /** + * Retrieves the list of all the alternatives that this rule defines + * @return A list of alternatives, each of which is a string of tokens + * (either terminal or non-terminal) + */ List getAlternatives() { return m_alternatives; } + /** + * Retrieves the left-hand side symbol of the rule + * @return The left-hand side symbol + */ NonTerminalToken getLeftHandSide() { return m_leftHandSide; @@ -159,7 +199,7 @@ protected static String unescapeString(String s) } catch (IOException e) { - // TODO Auto-generated catch block + // Auto-generated catch block e.printStackTrace(); } return p.getProperty("key"); @@ -183,13 +223,6 @@ public String toString() return out.toString(); } - public TokenString tokenize(String s) - { - TokenString out = new TokenString(); - // TODO - return out; - } - public Set getTerminalTokens() { Set out = new HashSet(); @@ -200,6 +233,18 @@ public Set getTerminalTokens() return out; } + /** + * Adds a collection of alternatives to the rule + * @param alternatives The alternatives to add + */ + public void addAlternatives(Collection alternatives) + { + m_alternatives.addAll(alternatives); + } + + /** + * Exception thrown when the parsing of a rule form a string fails + */ public static class InvalidRuleException extends EmptyException { /** diff --git a/Source/Parsing/src/ca/uqac/lif/bullwinkle/BullwinkleCli.java b/Source/Parsing/src/ca/uqac/lif/bullwinkle/BullwinkleCli.java index 694c685..8ba4a0b 100644 --- a/Source/Parsing/src/ca/uqac/lif/bullwinkle/BullwinkleCli.java +++ b/Source/Parsing/src/ca/uqac/lif/bullwinkle/BullwinkleCli.java @@ -63,7 +63,8 @@ public class BullwinkleCli protected static final String VERSION_STRING = BullwinkleCli.class.getPackage().getImplementationVersion(); /** - * @param args + * Main loop + * @param args The command-line arguments */ public static void main(String[] args) { @@ -254,6 +255,12 @@ private static Options setupOptions() "Verbose messages with level x") .create(); options.addOption(opt); + opt = OptionBuilder + .withLongOpt("version") + .withDescription( + "Show version number") + .create(); + options.addOption(opt); return options; } diff --git a/Source/Parsing/src/ca/uqac/lif/bullwinkle/NonTerminalToken.java b/Source/Parsing/src/ca/uqac/lif/bullwinkle/NonTerminalToken.java index ba48bd9..d128f4b 100644 --- a/Source/Parsing/src/ca/uqac/lif/bullwinkle/NonTerminalToken.java +++ b/Source/Parsing/src/ca/uqac/lif/bullwinkle/NonTerminalToken.java @@ -34,5 +34,5 @@ public boolean matches(final Token tok) public int match(final String s) { return 0; - } + } } diff --git a/Source/Parsing/src/ca/uqac/lif/bullwinkle/Token.java b/Source/Parsing/src/ca/uqac/lif/bullwinkle/Token.java index 410214a..d09f4c1 100644 --- a/Source/Parsing/src/ca/uqac/lif/bullwinkle/Token.java +++ b/Source/Parsing/src/ca/uqac/lif/bullwinkle/Token.java @@ -49,6 +49,21 @@ public int hashCode() return m_name.hashCode(); } + @Override + public boolean equals(Object o) + { + if (o == null || !(o instanceof Token)) + { + return false; + } + return equals((Token) o); + } + + protected boolean equals(Token t) + { + return t.getName().compareTo(m_name) == 0; + } + public abstract boolean matches(final Token tok); public abstract int match(final String s); diff --git a/Source/Parsing/src/ca/uqac/lif/util/FileReadWrite.java b/Source/Parsing/src/ca/uqac/lif/util/FileReadWrite.java index 5019939..0f3a40d 100644 --- a/Source/Parsing/src/ca/uqac/lif/util/FileReadWrite.java +++ b/Source/Parsing/src/ca/uqac/lif/util/FileReadWrite.java @@ -34,6 +34,7 @@ public class FileReadWrite * if some IOException is thrown. * @param filename The filename to write to * @param contents The file's contents + * @throws IOException If the writing fails */ public static void writeToFile(String filename, String contents) throws IOException { @@ -59,6 +60,7 @@ public static void writeToFile(String filename, String contents) throws IOExcep * @param filename The name (and path) of the file to read * @return The file's contents, and empty string if the file * does not exist + * @throws IOException If the reading fails */ public static String readFile(String filename) throws IOException { @@ -71,6 +73,7 @@ public static String readFile(String filename) throws IOException * @param f The file to read * @return The file's contents, and empty string if the file * does not exist + * @throws IOException If the reading fails */ public static /* @NonNull */ String readFile(File f) throws IOException { diff --git a/Source/Parsing/src/ca/uqac/lif/util/PackageFileReader.java b/Source/Parsing/src/ca/uqac/lif/util/PackageFileReader.java index bdeab00..52a0bc9 100644 --- a/Source/Parsing/src/ca/uqac/lif/util/PackageFileReader.java +++ b/Source/Parsing/src/ca/uqac/lif/util/PackageFileReader.java @@ -43,6 +43,7 @@ public static String readPackageFile(Class c, String path) * @param in The input stream to read * @return The file's contents, and empty string if the file * does not exist + * @throws IOException If the reading fails */ public static String readPackageFile(InputStream in) throws IOException { diff --git a/Source/ParsingTest/src/ca/uqac/lif/bullwinkle/GrammarTests.java b/Source/ParsingTest/src/ca/uqac/lif/bullwinkle/GrammarTests.java index d7a0654..f6f18f4 100644 --- a/Source/ParsingTest/src/ca/uqac/lif/bullwinkle/GrammarTests.java +++ b/Source/ParsingTest/src/ca/uqac/lif/bullwinkle/GrammarTests.java @@ -127,6 +127,20 @@ public void parseGrammar5() parseItNot("data/Grammar-10.bnf", "", expression, false); } + @Test + public void parseGrammar6() + { + String expression = "SELECT 0 AS att FROM 0 AS"; + parseItNot("data/Grammar-11.bnf", "", expression, false); + } + + @Test + public void parseGrammar7() + { + String expression = "THE TUPLES OF FILE \"a\" WHERE (a) = (0)"; + ParseNode node = parseIt("data/Grammar-11.bnf", "", expression, true); + } + @Test public void parseGrammarLtlFo1() { @@ -144,7 +158,7 @@ public void parseGrammarLtlFo1() public void parseGrammarWithEpsilon1() { String expression = "hello hello"; - ParseNode node = parseIt("data/Grammar-3.bnf", "", expression, true); + ParseNode node = parseIt("data/Grammar-3.bnf", "", expression, false); int size = node.getSize(); int expected_size = 6; if (size != expected_size) diff --git a/Source/ParsingTest/src/ca/uqac/lif/bullwinkle/ParserTest.java b/Source/ParsingTest/src/ca/uqac/lif/bullwinkle/ParserTest.java index f389644..26c0bd7 100644 --- a/Source/ParsingTest/src/ca/uqac/lif/bullwinkle/ParserTest.java +++ b/Source/ParsingTest/src/ca/uqac/lif/bullwinkle/ParserTest.java @@ -91,7 +91,6 @@ public void simpleValidGrammarFromFile() { fail("Valid grammar has thrown an exception when parsed."); } - System.out.println(parser); } } diff --git a/Source/ParsingTest/src/ca/uqac/lif/bullwinkle/data/Grammar-11.bnf b/Source/ParsingTest/src/ca/uqac/lif/bullwinkle/data/Grammar-11.bnf new file mode 100644 index 0000000..133baf9 --- /dev/null +++ b/Source/ParsingTest/src/ca/uqac/lif/bullwinkle/data/Grammar-11.bnf @@ -0,0 +1,99 @@ + +# Top production rule + + := | ; + +# Types + + := ^\d+; + := TRUE | FALSE ; + := ^\$[\w\d]+; + +# Built-in processors + + := | | | + | | | | ; + := FREEZE ; + := ( ) ON A WINDOW OF ; + := EVERY OF ( ) ; + := ST | ND | RD | TH ; + := OF ( ) ; + := COMBINE ( ) WITH ; + := PRINT ( ) ; + + +# Definition of a new processor + + := LET BE ( ) ; + := ^.*?(?=when); + +# User-defined processors. Rules get dynamically added here + + := gnarfnfar ; + + := FILE ; + := ^".*?"; + + + +# Primitive types + + := true | false ; + := ^\d+; + := ^".*?"; + := ^[a-zA-Z]\w*; + +# Constant processor + + := | | ; + +# Top-level EML symbols + + := | | + | ; + +# "SELECT" statement + + := SELECT FROM ; + +# List of named processors + + := ( ) | ; + := ( ) AS + | AS ; + := | ; + := , | ; + +# List of named attributes + + := ; + := AS ; + := | ; + := , | ; + +# Attribute expressions + + := | + | ; + := | ; + := . ; + := ; + := | ; + := ; + := ; + +# Binary operators + + := | ; + := ( ) + ( ) ; + := ( ) = ( ) ; + +# Tuple feeder + + := THE TUPLES OF ; + +# "WHERE" statement + + := WHERE ; + + \ No newline at end of file diff --git a/config.xml b/config.xml index 255ecb8..cc479fe 100644 --- a/config.xml +++ b/config.xml @@ -26,7 +26,7 @@ Bullwinkle - 1.1.4 + 1.1.5