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 }