// 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;
}
}