~ubuntu-branches/ubuntu/gutsy/jflex/gutsy

« back to all changes in this revision

Viewing changes to src/JFlex/SemCheck.java

  • Committer: Bazaar Package Importer
  • Author(s): Takashi Okamoto
  • Date: 2002-02-16 13:38:21 UTC
  • Revision ID: james.westby@ubuntu.com-20020216133821-5wsdprpt9xl7ondr
Tags: upstream-1.3.5
ImportĀ upstreamĀ versionĀ 1.3.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
2
 * JFlex 1.3.5                                                             *
 
3
 * Copyright (C) 1998-2001  Gerwin Klein <lsf@jflex.de>                    *
 
4
 * All rights reserved.                                                    *
 
5
 *                                                                         *
 
6
 * This program is free software; you can redistribute it and/or modify    *
 
7
 * it under the terms of the GNU General Public License. See the file      *
 
8
 * COPYRIGHT for more information.                                         *
 
9
 *                                                                         *
 
10
 * This program is distributed in the hope that it will be useful,         *
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
 
13
 * GNU General Public License for more details.                            *
 
14
 *                                                                         *
 
15
 * You should have received a copy of the GNU General Public License along *
 
16
 * with this program; if not, write to the Free Software Foundation, Inc., *
 
17
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                 *
 
18
 *                                                                         *
 
19
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
20
package JFlex;
 
21
 
 
22
import java.util.*;
 
23
import java.io.File;
 
24
 
 
25
/**
 
26
 * Performs simple semantic analysis on regular expressions.
 
27
 *
 
28
 * (used for checking if trailing contexts are legal)
 
29
 *
 
30
 * @author Gerwin Klein
 
31
 * @version JFlex 1.3.5, $Revision: 1.15 $, $Date: 2001/10/08 10:08:05 $
 
32
 */
 
33
public final class SemCheck {
 
34
 
 
35
  // stored globally since they are used as constants in all checks
 
36
  private static Macros macros;
 
37
  private static char maxChar;
 
38
 
 
39
 
 
40
  /**
 
41
   * Performs semantic analysis for all expressions.
 
42
   *
 
43
   * Currently: illegal lookahead check only
 
44
   * [fixme: more checks possible]
 
45
   *
 
46
   * @param rs   the reg exps to be checked
 
47
   * @param m    the macro table (in expanded form)
 
48
   * @param max  max character of the used charset (for negation)
 
49
   * @param f    the spec file containing the rules [fixme]
 
50
   */
 
51
  public static void check(RegExps rs, Macros m, char max, File f) {
 
52
    macros = m;
 
53
    maxChar = max;
 
54
    
 
55
    boolean errors = false;
 
56
    int num = rs.getNum();
 
57
    for (int i = 0; i < num; i++) {
 
58
      RegExp r = rs.getRegExp(i);
 
59
      RegExp l = rs.getLookAhead(i);
 
60
     
 
61
      if (!checkLookAhead(r,l)) {
 
62
        errors = true;
 
63
        Out.error(f, ErrorMessages.LOOKAHEAD_ERROR, rs.getLine(i), -1);
 
64
      }
 
65
    }
 
66
    
 
67
    if (errors) throw new GeneratorException();
 
68
  }
 
69
 
 
70
 
 
71
  /**
 
72
   * Checks for illegal lookahead expressions. 
 
73
   * 
 
74
   * Lookahead in JFlex only works when the first expression has fixed
 
75
   * length or when the intersection of the last set of the first expression
 
76
   * and the first set of the second expression is empty.
 
77
   *
 
78
   * @param r1   first regexp
 
79
   * @param r2   second regexp (the lookahead)
 
80
   *
 
81
   * @return true iff JFlex can generate code for the lookahead expression
 
82
   */
 
83
  private static boolean checkLookAhead(RegExp r1, RegExp r2) {
 
84
    return r2 == null || length(r1) > 0 || !(last(r1).and(first(r2)).containsElements());
 
85
  }
 
86
 
 
87
 
 
88
  /**
 
89
   * Returns length if expression has fixed length, -1 otherwise.   
 
90
   */
 
91
  private static int length(RegExp re) {
 
92
    RegExp2 r;
 
93
 
 
94
    switch (re.type) {      
 
95
 
 
96
    case sym.BAR: {
 
97
      r = (RegExp2) re;
 
98
      int l1 = length(r.r1);
 
99
      if (l1 < 0) return -1;
 
100
      int l2 = length(r.r2);
 
101
 
 
102
      if (l1 == l2) 
 
103
        return l1;
 
104
      else
 
105
        return -1;
 
106
    }
 
107
 
 
108
    case sym.CONCAT: {
 
109
      r = (RegExp2) re;
 
110
      int l1 = length(r.r1);
 
111
      if (l1 < 0) return -1;
 
112
      int l2 = length(r.r2);
 
113
      if (l2 < 0) return -1;
 
114
      return l1+l2;
 
115
    }
 
116
 
 
117
    case sym.STAR:
 
118
    case sym.PLUS:
 
119
    case sym.QUESTION:
 
120
      return -1;
 
121
 
 
122
    case sym.CCLASS:
 
123
    case sym.CCLASSNOT:
 
124
    case sym.CHAR:
 
125
      return 1;
 
126
 
 
127
    case sym.STRING: {
 
128
      String content = (String) ((RegExp1) re).content;
 
129
      return content.length();
 
130
    }
 
131
 
 
132
    case sym.MACROUSE:      
 
133
      return length(macros.getDefinition((String) ((RegExp1) re).content));
 
134
    }
 
135
 
 
136
    throw new Error("Unkown expression type "+re.type+" in "+re);  
 
137
  }
 
138
  
 
139
 
 
140
  /**
 
141
   * Returns true iff the matched language contains epsilon
 
142
   */
 
143
  private static boolean containsEpsilon(RegExp re) {
 
144
    RegExp2 r;
 
145
 
 
146
    switch (re.type) {      
 
147
 
 
148
    case sym.BAR:
 
149
      r = (RegExp2) re;
 
150
      return containsEpsilon(r.r1) || containsEpsilon(r.r2);
 
151
 
 
152
    case sym.CONCAT:
 
153
      r = (RegExp2) re;
 
154
      if (containsEpsilon(r.r1))
 
155
        return containsEpsilon(r.r2);
 
156
      else
 
157
        return false;         
 
158
 
 
159
    case sym.STAR:
 
160
    case sym.QUESTION:
 
161
      return true;
 
162
 
 
163
    case sym.PLUS:
 
164
      return containsEpsilon( (RegExp) ((RegExp1)re).content );
 
165
 
 
166
    case sym.CCLASS:     
 
167
    case sym.CCLASSNOT:
 
168
    case sym.CHAR:
 
169
      return false;
 
170
 
 
171
    case sym.STRING:
 
172
      return ((String) ((RegExp1) re).content).length() <= 0;
 
173
 
 
174
    case sym.MACROUSE:
 
175
      return containsEpsilon(macros.getDefinition((String) ((RegExp1) re).content));
 
176
    }
 
177
 
 
178
    throw new Error("Unkown expression type "+re.type+" in "+re);
 
179
  }
 
180
 
 
181
 
 
182
  /**
 
183
   * Returns the first set of an expression. 
 
184
   *
 
185
   * (the first-character-projection of the language)
 
186
   */
 
187
  private static IntCharSet first(RegExp re) {
 
188
    RegExp2 r;
 
189
 
 
190
    switch (re.type) {      
 
191
 
 
192
    case sym.BAR:
 
193
      r = (RegExp2) re;
 
194
      return first(r.r1).add(first(r.r2));
 
195
 
 
196
    case sym.CONCAT:
 
197
      r = (RegExp2) re;
 
198
      if ( containsEpsilon(r.r1) ) 
 
199
        return first(r.r1).add(first(r.r2));      
 
200
      else
 
201
        return first(r.r1);
 
202
 
 
203
    case sym.STAR:
 
204
    case sym.PLUS:
 
205
    case sym.QUESTION:
 
206
      return first((RegExp) ((RegExp1)re).content);
 
207
 
 
208
    case sym.CCLASS:
 
209
      return new IntCharSet((Vector) ((RegExp1) re).content);
 
210
 
 
211
    case sym.CCLASSNOT:
 
212
      IntCharSet all = new IntCharSet(new Intervall( (char) 0,maxChar));
 
213
      IntCharSet set = new IntCharSet((Vector) ((RegExp1) re).content);
 
214
      all.sub(set);
 
215
      return all;
 
216
 
 
217
    case sym.CHAR:
 
218
      return new IntCharSet(((Character) ((RegExp1) re).content).charValue());
 
219
 
 
220
    case sym.STRING:
 
221
      String content = (String) ((RegExp1) re).content;
 
222
      if (content.length() > 0)
 
223
        return new IntCharSet(content.charAt(0));
 
224
      else
 
225
        return new IntCharSet();
 
226
 
 
227
    case sym.MACROUSE:      
 
228
      return first(macros.getDefinition((String) ((RegExp1) re).content));
 
229
    }
 
230
 
 
231
    throw new Error("Unkown expression type "+re.type+" in "+re);
 
232
  }
 
233
 
 
234
 
 
235
  /**
 
236
   * Returns the last set of the expression
 
237
   *
 
238
   * (the last-charater-projection of the language)
 
239
   */
 
240
  private static IntCharSet last(RegExp re) {
 
241
 
 
242
    RegExp2 r;
 
243
 
 
244
    switch (re.type) {      
 
245
 
 
246
    case sym.BAR:
 
247
      r = (RegExp2) re;
 
248
      return last(r.r1).add(last(r.r2));
 
249
 
 
250
    case sym.CONCAT:
 
251
      r = (RegExp2) re;
 
252
      if ( containsEpsilon(r.r2) )
 
253
        return last(r.r1).add(last(r.r2));
 
254
      else
 
255
        return last(r.r2);
 
256
 
 
257
    case sym.STAR:
 
258
    case sym.PLUS:
 
259
    case sym.QUESTION:
 
260
      return last((RegExp) ((RegExp1)re).content);
 
261
 
 
262
    case sym.CCLASS:
 
263
      return new IntCharSet((Vector) ((RegExp1) re).content);
 
264
 
 
265
    case sym.CCLASSNOT:
 
266
      IntCharSet all = new IntCharSet(new Intervall( (char) 0,maxChar));
 
267
      IntCharSet set = new IntCharSet((Vector) ((RegExp1) re).content);
 
268
      all.sub(set);
 
269
      return all;
 
270
 
 
271
    case sym.CHAR:
 
272
      return new IntCharSet(((Character) ((RegExp1) re).content).charValue());
 
273
 
 
274
    case sym.STRING:
 
275
      String content = (String) ((RegExp1) re).content;
 
276
      if (content.length() > 0)
 
277
        return new IntCharSet(content.charAt(content.length()-1));
 
278
      else
 
279
        return new IntCharSet();
 
280
 
 
281
    case sym.MACROUSE:      
 
282
      return last(macros.getDefinition((String) ((RegExp1) re).content));
 
283
    }
 
284
 
 
285
    throw new Error("Unkown expression type "+re.type+" in "+re);
 
286
  }
 
287
}