// This file is part of AceWiki. // Copyright 2008-2013, AceWiki developers. // // AceWiki is free software: you can redistribute it and/or modify it under the terms of the GNU // Lesser General Public License as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // AceWiki is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License along with AceWiki. If // not, see http://www.gnu.org/licenses/. package ch.uzh.ifi.attempto.chartparser; import java.util.HashMap; import java.util.List; /** * This class represents a grammar rule. A grammar rule consists of a nonterminal category (called * "head") and a sequence of categories (called "body"). Furthermore, a grammar rule can be * scope-closing, which means that all scopes opened by its children are closed at the position * after the last child category. * * @author Tobias Kuhn */ public class GrammarRule { private final Nonterminal head; private final boolean scopeclosing; private final Category[] body; private final Annotation annotation; /** * Creates a new grammar rule. * * @param annotation The annotation object. * @param head The head category. * @param scopeclosing Defines whether the rule is scope-closing or not. * @param body The category sequence of the body. */ public GrammarRule(Annotation annotation, Nonterminal head, boolean scopeclosing, Category... body) { this.head = head; this.body = body; this.scopeclosing = scopeclosing; if (annotation == null) { this.annotation = new Annotation(); } else { this.annotation = annotation; } } /** * Creates a new grammar rule. * * @param head The head category. * @param scopeclosing Defines whether the rule is scope-closing or not. * @param body The category sequence of the body. */ public GrammarRule(Nonterminal head, boolean scopeclosing, Category... body) { this(null, head, scopeclosing, body); } /** * Creates a new grammar rule that is not scope-closing. * * @param head The head category. * @param body The body category sequence. */ public GrammarRule(Nonterminal head, Category... body) { this(null, head, false, body); } /** * Creates a new grammar rule. * * @param annotation The annotation object. * @param categories The first category of this list stands for the head category (it has to be * a Nonterminal object). The rest stands for the body categories. * @param scopeclosing Defines whether the rule is scope-closing or not. */ public GrammarRule(Annotation annotation, List<Category> categories, boolean scopeclosing) { this.scopeclosing = scopeclosing; this.head = (Nonterminal) categories.get(0); categories.remove(0); this.body = categories.toArray(new Category[0]); if (annotation == null) { this.annotation = new Annotation(); } else { this.annotation = annotation; } } /** * Returns the head category of this grammar rule. * * @return The head category. */ public Nonterminal getHead() { return head; } /** * Returns the body category sequence of this grammar rule. * * @return The body category sequence. */ public Category[] getBody() { return body; } /** * Returns true if the body is empty. Such grammar rules are called "epsilon rules". * * @return true if the body is empty. */ public boolean hasEmptyBody() { return body.length == 0; } /** * Returns the first category of the body. * * @return The first category of the body. */ public Category getFirst() { return body[0]; } /** * Returns true if the rule is scope-closing. * * @return true if the rule is scope-closing. */ public boolean isScopeClosing() { return scopeclosing; } /** * Returns the annotation object of this rule. * * @return The annotation object. */ public Annotation getAnnotation() { return annotation; } /** * Creates a deep copy of this rule. * * @return A deep copy. */ public GrammarRule deepCopy() { return deepCopy(new HashMap<Integer, StringObject>()); } /** * Creates a deep copy of this rule using the given string objects. This method is * usually called form another deepCopy-method. * * @param stringObjs The string objects to be used. * @return A deep copy. */ GrammarRule deepCopy(HashMap<Integer, StringObject> stringObjs) { Nonterminal headC = (Nonterminal) head.deepCopy(stringObjs); Category[] bodyC = new Category[body.length]; for (int i=0; i < body.length ; i++) { bodyC[i] = body[i].deepCopy(stringObjs); } Annotation annotationC = annotation.deepCopy(stringObjs); return new GrammarRule(annotationC, headC, scopeclosing, bodyC); } public String toString() { String s = head + " "; if (scopeclosing) { s += "~>"; } else { s += "=>"; } for (Category c : body) { s += " " + c; } return s; } }