001: package fri.patterns.interpreter.parsergenerator.util;
002:
003: import java.io.File;
004: import java.util.*;
005: import fri.patterns.interpreter.parsergenerator.Token;
006: import fri.patterns.interpreter.parsergenerator.syntax.*;
007: import fri.patterns.interpreter.parsergenerator.syntax.builder.*;
008:
009: /**
010: SyntaxChecker checks a EBNF syntax (file) for following things:
011: <ul>
012: <li>unresolved nonterminals (nonterminals without rule)</li>
013: <li>singular rules (nonterminal can be substituted by its singular right symbol)</li>
014: <li>isolated rules (redundant, can be removed)</li>
015: <li>None or more than one toplevel rule</li>
016: </ul>
017: <pre>
018: SYNTAX: java fri.patterns.interpreter.parsergenerator.util.SyntaxChecker file.syntax [file.syntax ...]
019: </pre>
020:
021: @author (c) 2000, Fritz Ritzberger
022: */
023:
024: public class SyntaxChecker {
025: private boolean diagnosis = true;
026:
027: public SyntaxChecker(Object syntaxFile) throws Exception {
028: this (new SyntaxBuilder(syntaxFile).getSyntax());
029: }
030:
031: public SyntaxChecker(Syntax syntax) {
032: if (syntax.size() <= 0) {
033: System.out.println("ERROR: Found no rules in syntax!");
034: diagnosis = false;
035: return;
036: }
037:
038: System.out
039: .println("Number of rules (after resolving parenthesis, alternations and wildcards): "
040: + syntax.size());
041:
042: // Find start rule(s)
043: List topLevelRules = syntax.findStartRules();
044: if (topLevelRules.size() > 1) {
045: System.out
046: .println("WARNING: More than one toplevel rules:");
047: for (int i = 0; i < topLevelRules.size(); i++)
048: System.out.println(" " + topLevelRules.get(i));
049: } else if (topLevelRules.size() < 1) {
050: System.out
051: .println("WARNING: Found no toplevel rule, first rule (default START rule) is: "
052: + syntax.getRule(0));
053: } else {
054: System.out.println("Start rule is \""
055: + topLevelRules.get(0) + "\"");
056: }
057:
058: // check for unresolved nonterminals
059: Set unresolved = syntax.getUnresolvedNonterminals();
060: if (unresolved.size() > 0) {
061: System.out.println("Found " + unresolved.size()
062: + " unresolved nonterminals:");
063: diagnosis = false;
064: for (Iterator it = unresolved.iterator(); it.hasNext();)
065: System.out.println(" " + it.next());
066: } else {
067: System.out.println("Found no unresolved nonterminals.");
068: }
069:
070: // check for isolated rules
071: for (int i = syntax.size() - 1; i >= 0; i--) {
072: Rule rule = syntax.getRule(i);
073:
074: boolean found = topLevelRules.contains(rule)
075: || rule.getNonterminal().equals(Token.TOKEN)
076: || rule.getNonterminal().equals(Token.IGNORED);
077:
078: for (int j = 0; found == false && j < syntax.size(); j++) {
079: if (j != i) {
080: Rule rule2 = syntax.getRule(j);
081: for (int k = 0; found == false
082: && k < rule2.rightSize(); k++)
083: if (rule2.getRightSymbol(k).equals(
084: rule.getNonterminal()))
085: found = true;
086: }
087: }
088:
089: if (found == false)
090: System.out
091: .println("WARNING: Found isolated (unused, redundant) rule: "
092: + rule);
093: }
094:
095: // check for singular rules
096: int singulars = 0;
097: for (int i = syntax.size() - 1; i >= 0; i--) {
098: Rule rule = syntax.getRule(i);
099: boolean singular = (rule.rightSize() == 1 && topLevelRules
100: .contains(rule) == false); // has only one symbol on right side
101:
102: // check if defined only once on any left side
103: for (int j = 0; singular && j < syntax.size(); j++)
104: if (j != i
105: && syntax.getRule(j).getNonterminal().equals(
106: rule.getNonterminal()))
107: singular = false; // nonterm has been found once more on left side
108:
109: if (singular) {
110: System.out
111: .println("INFO: Found singular rule (nonterminal could be substituted by its right symbol): "
112: + rule);
113: singulars++;
114: }
115: }
116: System.out.println("Found " + singulars + " singular rules.");
117: }
118:
119: /** Returns false when the checked syntax is not able to be used as lexer or parser configuration. */
120: public boolean getDiagnosis() {
121: return diagnosis;
122: }
123:
124: public static void main(String[] args) {
125: if (args.length <= 0) {
126: System.err.println("SYNTAX: java "
127: + SyntaxChecker.class.getName()
128: + " file.syntax [file.syntax ...]");
129: System.err
130: .println(" Prints out a diagnosis of passed syntax file(s).");
131: System.exit(2);
132: }
133:
134: boolean ok = true;
135: for (int i = 0; i < args.length; i++) {
136: try {
137: SyntaxChecker checker = new SyntaxChecker(new File(
138: args[i]));
139: ok = ok && checker.getDiagnosis();
140: } catch (Exception e) {
141: ok = false;
142: e.printStackTrace();
143: }
144: }
145:
146: System.exit(ok ? 0 : 1);
147: }
148:
149: }
|