001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2004-2007 Robert Grimm
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * version 2 as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
017: * USA.
018: */
019: package xtc.parser;
020:
021: import java.util.ArrayList;
022: import java.util.List;
023:
024: import xtc.util.Utilities;
025:
026: /**
027: * A semantic action.
028: *
029: * @author Robert Grimm
030: * @version $Revision: 1.22 $
031: */
032: public class Action extends Element {
033:
034: /**
035: * The list of source lines for the semantic action. Note that each
036: * source line is a string without the terminating end-of-line
037: * character(s).
038: */
039: public final List<String> code;
040:
041: /**
042: * The list of indentation levels, one per line of code. Note that
043: * this list must be at least as long as the list of source lines.
044: */
045: public final List<Integer> indent;
046:
047: /**
048: * Create a new action with the specified code. The specified
049: * string is broken up into individual lines, removing all
050: * end-of-line characters along the way.
051: *
052: * @param s The code as a string.
053: * @param indent The list of indentation levels, one per line
054: * in the specified string.
055: * @throws IllegalArgumentException
056: * Signals that <code>indent</code> is too short.
057: */
058: public Action(String s, List<Integer> indent) {
059: String[] ss = Utilities.SPACE_NEWLINE_SPACE.split(s);
060: this .indent = indent;
061:
062: if (indent.size() < ss.length) {
063: throw new IllegalArgumentException(
064: "List of indentation levels too short");
065: }
066:
067: // Trim lines and eliminate empty lines at the beginning and end.
068: if (0 < ss.length) {
069: // We only need to trim the first and last line.
070: ss[0] = ss[0].trim();
071: if (1 != ss.length) {
072: ss[ss.length - 1] = ss[ss.length - 1].trim();
073: }
074: }
075:
076: // Find empty lines at beginning and end.
077: int start = ss.length;
078: int end = ss.length - 1;
079:
080: for (int i = 0; i < ss.length; i++) {
081: if (!"".equals(ss[i])) {
082: start = i;
083: break;
084: }
085: }
086:
087: for (int i = ss.length - 1; i >= 0; i--) {
088: if (!"".equals(ss[i])) {
089: end = i;
090: break;
091: }
092: }
093:
094: // Remove empty lines from beginning and end.
095: int size = indent.size();
096: for (int i = 0; i < start; i++) {
097: indent.remove(0);
098: }
099:
100: for (int i = end + 1; i < size; i++) {
101: indent.remove(indent.size() - 1);
102: }
103:
104: code = new ArrayList<String>(end - start + 1);
105: for (int i = start; i <= end; i++) {
106: code.add(ss[i]);
107: }
108: }
109:
110: /**
111: * Create a new action with the specified code.
112: *
113: * @param code The code as a list source lines.
114: * @param indent The corresponding indentation levels.
115: * @throws IllegalArgumentException
116: * Signals that the number of code lines is inconsistent with the
117: * number of indentation levels.
118: */
119: public Action(List<String> code, List<Integer> indent) {
120: if (indent.size() != code.size()) {
121: throw new IllegalArgumentException(
122: "Number of code lines and "
123: + "indentation levels inconsistent");
124: }
125: this .code = code;
126: this .indent = indent;
127: }
128:
129: public Tag tag() {
130: return Tag.ACTION;
131: }
132:
133: /**
134: * Add the specified action to this action.
135: *
136: * @param a The action to add.
137: */
138: public void add(Action a) {
139: code.addAll(a.code);
140: indent.addAll(a.indent);
141: }
142:
143: /**
144: * Determine whether this action sets the {@link CodeGenerator#VALUE
145: * semantic value}. This method implements a conservative
146: * approximation by searching for occurrences of the corresponding
147: * variable name.
148: *
149: * @return <code>true</code> if this action sets the semantic value.
150: */
151: public boolean setsValue() {
152: for (String s : code) {
153: if (-1 != s.indexOf(CodeGenerator.VALUE)) {
154: return true;
155: }
156: }
157: return false;
158: }
159:
160: public int hashCode() {
161: return code.hashCode();
162: }
163:
164: public boolean equals(Object o) {
165: if (this == o)
166: return true;
167: if (!(o instanceof Action))
168: return false;
169: Action other = (Action) o;
170: if (!code.equals(other.code))
171: return false;
172: return indent.equals(other.indent);
173: }
174:
175: }
|