001 // This file is part of AceWiki.
002 // Copyright 2008-2012, AceWiki developers.
003 //
004 // AceWiki is free software: you can redistribute it and/or modify it under the terms of the GNU
005 // Lesser General Public License as published by the Free Software Foundation, either version 3 of
006 // the License, or (at your option) any later version.
007 //
008 // AceWiki is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
009 // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
010 // Lesser General Public License for more details.
011 //
012 // You should have received a copy of the GNU Lesser General Public License along with AceWiki. If
013 // not, see http://www.gnu.org/licenses/.
014
015 package ch.uzh.ifi.attempto.chartparser;
016
017 import java.util.HashMap;
018 import java.util.List;
019
020 /**
021 * This class represents a grammar rule. A grammar rule consists of a nonterminal category (called
022 * "head") and a sequence of categories (called "body"). Furthermore, a grammar rule can be
023 * scope-closing, which means that all scopes opened by its children are closed at the position
024 * after the last child category.
025 *
026 * @author Tobias Kuhn
027 */
028 public class GrammarRule {
029
030 private final Nonterminal head;
031 private final boolean scopeclosing;
032 private final Category[] body;
033 private final Annotation annotation;
034
035 /**
036 * Creates a new grammar rule.
037 *
038 * @param annotation The annotation object.
039 * @param head The head category.
040 * @param scopeclosing Defines whether the rule is scope-closing or not.
041 * @param body The category sequence of the body.
042 */
043 public GrammarRule(Annotation annotation, Nonterminal head, boolean scopeclosing, Category... body) {
044 this.head = head;
045 this.body = body;
046 this.scopeclosing = scopeclosing;
047 if (annotation == null) {
048 this.annotation = new Annotation();
049 } else {
050 this.annotation = annotation;
051 }
052 }
053
054 /**
055 * Creates a new grammar rule.
056 *
057 * @param head The head category.
058 * @param scopeclosing Defines whether the rule is scope-closing or not.
059 * @param body The category sequence of the body.
060 */
061 public GrammarRule(Nonterminal head, boolean scopeclosing, Category... body) {
062 this(null, head, scopeclosing, body);
063 }
064
065 /**
066 * Creates a new grammar rule that is not scope-closing.
067 *
068 * @param head The head category.
069 * @param body The body category sequence.
070 */
071 public GrammarRule(Nonterminal head, Category... body) {
072 this(null, head, false, body);
073 }
074
075 /**
076 * Creates a new grammar rule.
077 *
078 * @param annotation The annotation object.
079 * @param categories The first category of this list stands for the head category (it has to be
080 * a Nonterminal object). The rest stands for the body categories.
081 * @param scopeclosing Defines whether the rule is scope-closing or not.
082 */
083 public GrammarRule(Annotation annotation, List<Category> categories, boolean scopeclosing) {
084 this.scopeclosing = scopeclosing;
085 this.head = (Nonterminal) categories.get(0);
086 categories.remove(0);
087 this.body = categories.toArray(new Category[0]);
088 if (annotation == null) {
089 this.annotation = new Annotation();
090 } else {
091 this.annotation = annotation;
092 }
093 }
094
095 /**
096 * Returns the head category of this grammar rule.
097 *
098 * @return The head category.
099 */
100 public Nonterminal getHead() {
101 return head;
102 }
103
104 /**
105 * Returns the body category sequence of this grammar rule.
106 *
107 * @return The body category sequence.
108 */
109 public Category[] getBody() {
110 return body;
111 }
112
113 /**
114 * Returns true if the body is empty. Such grammar rules are called "epsilon rules".
115 *
116 * @return true if the body is empty.
117 */
118 public boolean hasEmptyBody() {
119 return body.length == 0;
120 }
121
122 /**
123 * Returns the first category of the body.
124 *
125 * @return The first category of the body.
126 */
127 public Category getFirst() {
128 return body[0];
129 }
130
131 /**
132 * Returns true if the rule is scope-closing.
133 *
134 * @return true if the rule is scope-closing.
135 */
136 public boolean isScopeClosing() {
137 return scopeclosing;
138 }
139
140 /**
141 * Returns the annotation object of this rule.
142 *
143 * @return The annotation object.
144 */
145 public Annotation getAnnotation() {
146 return annotation;
147 }
148
149 /**
150 * Creates a deep copy of this rule.
151 *
152 * @return A deep copy.
153 */
154 public GrammarRule deepCopy() {
155 return deepCopy(new HashMap<Integer, StringObject>());
156 }
157
158 /**
159 * Creates a deep copy of this rule using the given string objects. This method is
160 * usually called form another deepCopy-method.
161 *
162 * @param stringObjs The string objects to be used.
163 * @return A deep copy.
164 */
165 GrammarRule deepCopy(HashMap<Integer, StringObject> stringObjs) {
166 Nonterminal headC = (Nonterminal) head.deepCopy(stringObjs);
167 Category[] bodyC = new Category[body.length];
168 for (int i=0; i < body.length ; i++) {
169 bodyC[i] = body[i].deepCopy(stringObjs);
170 }
171 Annotation annotationC = annotation.deepCopy(stringObjs);
172 return new GrammarRule(annotationC, headC, scopeclosing, bodyC);
173 }
174
175 public String toString() {
176 String s = head + " ";
177 if (scopeclosing) {
178 s += "~>";
179 } else {
180 s += "=>";
181 }
182 for (Category c : body) {
183 s += " " + c;
184 }
185 return s;
186 }
187
188 }