KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jbet > Lexer


1 /*
2  * JBET - Java Binary Enhancement Tool
3  * Copyright (c) 2003 Networks Associates Technology, Inc.
4  *
5  * This software was developed under DARPA/SPAWAR contract
6  * N66001-00-C-8602 "SPMA" as part of the
7  * DARPA OASIS research program.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */

30
31 package jbet;
32 import java.io.*;
33 import java.util.*;
34
35 /**
36  * Lexical analyzer for JBET. This methods is used to lex
37  * command lines/files, and JBET assembler. This lexer uses
38  * a maximum of 2 lookahead character and tokens.
39  *
40  * This file contains fields that store
41  * 1) the lexer's current state
42  * 2) the input stream
43  * 3) the state stack
44  * 4) the look ahead buffers for characters and tokens.
45  *
46  * This class has many externally used methods marked by "used externally."
47  * The readch_lowlevel() and read_token() methods do most of the work. TBC.
48  *
49  * $Id: Lexer.java,v 1.22 2003/09/09 17:31:54 areisse Exp $
50  *
51  * @author Larry D'Anna
52  * @version
53  */

54
55
56 public class Lexer {
57
58     abstract class SimpleStream {
59     abstract public int read() throws IOException ;
60     String JavaDoc filename;
61     int line;
62     SimpleStream(String JavaDoc filename, int line) {
63         this.filename = filename;
64         this.line = line;
65     }
66     }
67
68     private SimpleStream in;
69
70
71     // lexer states
72
public static final int ST_TAG = 1; // only set by Jbet.doCommands
73
public static final int ST_OPT = 2; // expect a command opt. - set by ST_DASH
74
public static final int ST_DASH = 3;
75     public static final int ST_NORMAL = 4; // set by ST_DASH at end of opts.
76
public static final int ST_TYPE = 5;
77     public static final int ST_STRING = 6;
78     public static final int ST_CONST = 7;
79     public static final int ST_ASM = 8; // JBET assembler processing
80
public static final int ST_ASM_ARG = 9; // "
81
public static final int ST_COMMENT = 10;
82
83     static final int EOFCH = -1;
84     static final Token EOF = new Token(Token.EOF);
85     static final Token END_OF_OPTS = new Token(Token.END_OF_OPTS);
86     static final int SEMIHACKCH = 0x101;
87     
88     // used externally
89
int state; // Init'd by JbetdoCommands to ST_TAG
90

91
92     StringFunction varFunction = null;
93
94     private String JavaDoc doSub(String JavaDoc s) {
95     return varFunction.f(s);
96     }
97
98     /**
99      * Lexer state stack & its manipulation methods
100      * TBD why not use the Java stack object for this.
101      * Is it because of RuntimeException vs
102      * EmptyStackException in pop()?
103      *
104      */

105     private int [] stateStack = new int [5];
106     private int stateStacklen = 0;
107
108     // used externally
109
public void push(int s) {
110     stateStack[stateStacklen++] = state;
111     state = s;
112     if (stateStacklen == stateStack.length) {
113     // out of space so double the size of stateStack
114
int [] ss = new int [ stateStacklen * 2 ];
115         for (int i = 0; i < stateStacklen; i++)
116         ss[i] = stateStack[i];
117         stateStack = ss;
118     }
119     }
120     // used externally
121
public void pop() {
122     if (stateStacklen == 0) throw new RuntimeException JavaDoc
123         ("Lexer.pop called with empty stack");
124     state = stateStack[ --stateStacklen ];
125     }
126     
127     /**/
128
129     private Stack streams = new Stack();
130
131
132     private SimpleStream newStream(final Reader reader, final String JavaDoc fn, final int line) {
133     return new SimpleStream(fn, line) {
134         public int read() throws IOException { return reader.read(); };
135         };
136     }
137     private SimpleStream newStream(final InputStream inputStream, final String JavaDoc fn, final int line){
138     return new SimpleStream(fn, line) {
139         public int read() throws IOException { return inputStream.read(); };
140         };
141     }
142     
143     // Constructors
144
public Lexer (Reader reader, String JavaDoc fn) {
145     in = newStream(reader, fn, 1);
146     }
147     
148     public Lexer (InputStream is, String JavaDoc fn) {
149     in = newStream(is, fn, 1);
150     }
151
152     /* */
153
154     // Charcter reading methods
155

156     private int saveCh = -2;
157
158     /*
159      * This method does variable substitution, line numbering, and stream
160      * popping. All reads are through this method.
161      */

162     private int readch_lowlevel() throws ParseException {
163     int ch;
164     try {
165         if (saveCh == -2)
166         ch = in.read();
167         else {
168         ch = saveCh;
169         saveCh = -2;
170         }
171         if (ch == '%') {
172         saveCh = in.read();
173         if (saveCh == '(') {
174             saveCh = -2;
175             StringBuffer JavaDoc name = new StringBuffer JavaDoc();
176             boolean include = false;
177             while (true) {
178             ch = in.read();
179             if (ch==EOFCH) die ("unexpected end of file");
180             if (ch==' ' && name.toString().equals("include")) {
181                 //name.delete(0, name.length());
182
name = new StringBuffer JavaDoc(); //now it works with **antiquated** java
183
include = true;
184                 continue;
185             }
186             if (ch==')') break;
187             name.append((char) ch);
188             }
189             SimpleStream newstr;
190             if (!include) {
191             String JavaDoc value = doSub(name.toString());
192             if (value == null) throw new ParseException
193                 ("unknown variable: " + name);
194             newstr = newStream(new StringReader(value), in.filename, -1);
195             } else
196             newstr = newStream(new FileInputStream(name.toString()),
197                        name.toString(), 1);
198             streams.push(in);
199             in = newstr;
200             return readch_lowlevel();
201         }
202         }
203         if (ch == '\n' && in.line != -1)
204         in.line++;
205         if (ch == '\n' && (state == ST_ASM || state == ST_ASM_ARG))
206         ch = ';'; //HACK ALERT
207
if (ch == EOFCH && streams.size() != 0) {
208         in = (SimpleStream) streams.pop();
209         return readch_lowlevel();
210         }
211     } catch (IOException e) {
212         throw new ParseException ("IOException caught while parseing");
213     }
214
215     return ch;
216     }
217
218
219     /*
220      * Character lookahead (la) reading .
221      */

222     private static final int maxlaCh = 2;
223     private int [] laChar = new int [ maxlaCh ]; // char la buffer
224
private int numlaCh = 0; // # of chars currenty in la buffer
225
private int _justreadCh = -2; // most recient char.
226
// retrived by readch()
227

228     /*
229      * peek at the i'th character in the char la buffer.
230      */

231     private int laCh(int i) {
232     while (i > numlaCh) // add to the buffer if required
233
laChar[numlaCh++] = readch_lowlevel();
234     return laChar[i-1];
235     }
236
237    /*
238     * Unused. (XXX)
239     *
240     char laChar(int i) {
241          return (char) laCh(i);
242     }*/

243
244    /*
245     * Retrieve a character from the la buffer or from the stream
246     * and keep track of it in _justreadCh
247     */

248     private int readch() {
249     if (numlaCh == 0) {
250         _justreadCh = readch_lowlevel();
251     } else {
252         _justreadCh = laChar[0];
253         for (int i = 0; i < numlaCh - 1; i++)
254         laChar[i] = laChar[i+1];
255         numlaCh--;
256     }
257     return _justreadCh;
258     }
259
260     private int peekch() {
261     return laCh(1);
262     }
263
264     private char peekchar() {
265     return (char) peekch();
266     }
267     
268     private char readchar() {
269     return (char) readch();
270     }
271
272     /* */
273
274     /*
275      * Token lookahead (la) processing.
276      */

277     private static final int maxla = 2;
278     private Token [] laTok = new Token [maxla]; // token la buffer
279
private int numla = 0; // # of tokens currenty in la buffer
280
private Token _justread = null; // most recient token
281
// retrived by read()
282

283
284     /*
285      * peek at the i'th token in the token la buffer.
286      */

287     // used externally
288
Token la(int i) {
289     while (i > numla) // add to the buffer if required
290
laTok[numla++] = read_token();
291     return laTok[i - 1];
292     }
293
294     /*
295      * Unused. (XXX)
296      *
297     int latype(int i) {
298     return la(i).type;
299     }*/

300
301     // used externally
302
public Token peek() { return la(1); };
303     
304     public void setstate (int s) { state = s; }
305
306    /*
307     * Retrieve a token from the la buffer or from the stream
308     * and keep track of it in _justread
309     *
310     * Used in ClassInfo.java, FieldInfo.java ...
311     */

312     public Token read() {
313     if (numla == 0) {
314        _justread = read_token();
315     } else {
316         _justread = laTok[0];
317         for (int i = 0; i < numla - 1; i++)
318         laTok[i] = laTok[i+1];
319         numla--;
320     }
321     
322     return _justread;
323     }
324     
325     // used externally
326
public Token justread() { return _justread; };
327
328     /* */
329
330     private void skip_ws() {
331     while (true) {
332         if (! Character.isWhitespace(peekchar())) return;
333         readch();
334     }
335     }
336
337     private boolean border() {
338     return Character.isWhitespace(peekchar()) || peekch()==EOFCH;
339     }
340
341     // used externally
342
public void die(String JavaDoc msg) {
343     SimpleStream str = null;
344     if (in.line == -1)
345         for (int i = streams.size(); --i >= 0;) {
346         str = (SimpleStream) streams.elementAt(i);
347         if (str.line != -1) break;
348         }
349     else
350         str = in;
351
352     if (str==null || str.filename == null || str.line == -1)
353         throw new ParseException(msg + " " + (str.filename==null));
354     else
355         throw new ParseException(str.filename + " " + str.line + ": " + msg);
356     }
357
358     // used externally
359
public void unexpected(Token tok) {
360     die ("unexpected token: " + tok); // + " " + tok.type);
361
}
362
363     private static boolean isIdChar(char c) {
364     return c=='/' || c=='_' || c=='<' || c=='>' || c=='$' || c=='*' ||
365         Character.isLetterOrDigit(c);
366     }
367
368     /*
369      * Read in the (remaining?) characters of a STRING, OBJECT, CLASS, ...
370      * (see Type.java) identifier's name into StringBuffer text.
371      *
372      */

373     private void id(StringBuffer JavaDoc text) {
374     if (isIdChar(peekchar())) {
375         text.append(readchar());
376         while (true)
377         if (isIdChar(peekchar()))
378             text.append(readchar());
379         else
380             return;
381     } else
382         die("unexpected char '" + (char)peekch() + "'");
383     //die("an id must start with an underscore or a letter");
384
}
385
386     private void expectCh(char ch) {
387     if (peekch() != ch)
388         die ("expected: '" + ch + "'");
389     }
390
391     private void matchCh (StringBuffer JavaDoc text, char ch) {
392     expectCh(ch);
393     text.append( (char) readch() );
394     }
395
396     /*
397      * Fill StringBuffer text with a description of a type.
398      * Used by Lexer.read_token and Lexer.descriptor.
399      */

400     private void type(StringBuffer JavaDoc text) {
401     while (peekch() == '[') {
402         text.append((char) readch());
403     }
404     switch (peekch()) {
405     case 'B': case 'C': case 'D': case 'F': case 'I':
406     case 'J': case 'S': case 'Z': case 'V':
407         text.append((char) readch()); // BYTE CHAR, DOUBLE, ...
408
break;
409     case 'L': // STRING, OBJECT, CLASS, ...
410
text.append((char) readch());
411         id(text);
412         matchCh(text, ';');
413         break;
414     default:
415         die("unexpected char '" + (char)peekch() + "'");
416     }
417     }
418
419     /*
420      * Unused. (XXX)
421      *
422     private long integer() {
423     boolean negative = false;
424     if (peekch() == '-') {
425         negative = true;
426         readch();
427     }
428
429     int ret = readch() - '0';
430     while (peekch() >= '0' && peekch() <= '9')
431         ret = ret*10 + (readch() - '0');
432     return negative ? -ret : ret;
433     } */

434
435     /*
436      * Load decimal and hex integers (octal integers also) and floats
437      * into StringBuffer text. Does not care about size/length of the
438      * number.
439      */

440     private int number(StringBuffer JavaDoc text) {
441     boolean isfloat = false, hex = false, negative = false;
442     int digits_so_far = 0;
443     /*if (!(peekch() >= '0' && peekch() <= '9') && peekch() != '-')
444       die("unexpected char '" + (char)ch + "'"); /**/

445     for (;; text.append(readchar())) {
446         int ch = peekch();
447         if (ch >= '0' && ch <= '9') {
448         digits_so_far++;
449         } else if (ch == 'x' && digits_so_far==1 && !hex && !isfloat) {
450         hex = true;
451         } else if (ch == '.' && !hex && !isfloat) {
452         isfloat = true;
453         digits_so_far = 0;
454         } else if (ch == '-' && digits_so_far==0 && !isfloat && !negative){
455         negative = true;
456         } else if (digits_so_far == 0) {
457         die("unexpected char '" + (char)ch + "'");
458         } else {
459         return isfloat ? Token.FLOAT : Token.INT;
460         }
461     }
462     }
463
464     /*
465      * Load a character string, not including quote (single or double
466      * depeding on how this method is used, into StringBuffer text.
467      * Does not care about size/length of the string.
468      */

469     private void string(StringBuffer JavaDoc text, char quote) {
470     push(ST_STRING);
471     expectCh(quote);
472     readch();
473     while (true) {
474         int ch = readch(), ch2;
475
476         if (ch == quote) {
477         pop();
478         return;
479         }
480         switch (ch) {
481         case EOFCH:
482         die("unexpected end of file");
483         case '\\':
484         ch2 = readch();
485         switch (ch2) {
486         case EOFCH:
487             die("unexpected end of file");
488         case 'n':
489             text.append( '\n' );
490             break;
491         case 't':
492             text.append( '\t' );
493             break;
494         case 'r':
495             text.append( '\r' );
496             break;
497         default:
498             text.append( (char) ch2 );
499         }
500         break;
501         default:
502         text.append( (char) ch );
503         }
504     }
505     }
506     
507     private void descriptor(StringBuffer JavaDoc text) {
508     matchCh(text, '(');
509     while (peekch() != ')') {
510         type(text);
511     }
512     matchCh(text, ')');
513     type(text);
514     }
515     
516
517     private void matchString (StringBuffer JavaDoc text, String JavaDoc s) {
518     for (int i = 0; i < s.length(); i++)
519         matchCh(text, s.charAt(i));
520     }
521         
522
523     private Token read_token() {
524     bigdo:
525     do {
526         if (state != ST_OPT) skip_ws();
527         
528         /*
529          * // comment processing
530          */

531         if ( laCh(1) == '/' && laCh(2) == '/' ) {
532         push(ST_COMMENT);
533         readch(); readch();
534         while (true)
535             switch(readch()) {
536             case EOFCH:
537             die("unexpected end of file");
538             case '\n':
539             pop();
540             continue bigdo;
541             }
542         }
543
544         /*
545          * slash-asterisk ... asterisk-slash comment processing
546          */

547         if (laCh(1) == '/' && laCh(2) == '*') {
548         readch(); readch();
549         for (boolean last_was_star = false;;) {
550             int ch = readch();
551             if (ch == EOFCH) die ("unexpected end of file");
552             if (last_was_star && ch=='/') continue bigdo;
553             last_was_star = ch == '*';
554         }
555         }
556
557
558         StringBuffer JavaDoc text = new StringBuffer JavaDoc();
559         switch(state) {
560         case ST_TAG:
561         if (peekch() == EOFCH) return EOF;
562         if (peekch() == ';') return new Token(readch());
563         if (! Character.isLetter(peekchar()) && peekchar()!='_')
564             die ("unexpected char: '" + peekchar() + "'");
565         state = ST_DASH;
566         while (true) {
567             text.append( (char) readch() );
568             if (! Character.isLetter(peekchar()) && peekchar()!='_')
569             return new Token(Token.TAG, text.toString());
570         }
571
572         case ST_DASH:
573         //if (peekch() == EOFCH) return EOF;
574
if (peekch() != '-') {
575             state = ST_NORMAL;
576             return END_OF_OPTS;
577         }
578         readch();
579         if (border())
580             die("at least on option expected after a dash");
581         state = ST_OPT;
582         //fall through
583

584         case ST_OPT:
585         if (border()) {
586             state = ST_DASH;
587             continue bigdo;
588         }
589         return new Token(readch());
590
591         case ST_ASM_ARG:
592         case ST_NORMAL:
593         if (peekch() == EOFCH) return EOF;
594         if ((peekch() >= '0' && peekch() <= '9') || peekch() == '-')
595             try {
596             switch(number(text)) {
597             case Token.INT: return new Token(Token.INT, Long.parseLong(text.toString()));
598             case Token.FLOAT: return new Token(Token.FLOAT, Double.parseDouble(text.toString()));
599             }
600             } catch (NumberFormatException JavaDoc e) {
601             die ("bad number: " + e.getMessage());
602             }
603         if (isIdChar(peekchar())) {
604             id(text);
605             return new Token(Token.NAME, text.toString());
606         }
607
608         if (peekchar() == '[') {
609             //so we can do checkcast [I
610
type(text);
611             return new Token(Token.NAME, text.toString());
612         }
613
614         if (peekchar() == '@') {
615             text.append(readchar());
616             skip_ws();
617             if (peekchar()==EOFCH) die ("unexpected end of file");
618             while (true) {
619             if (Character.isWhitespace(peekchar()) ||
620                 peekch()==EOFCH) break;
621             text.append( readchar() );
622             }
623             return new Token(Token.NAME, text.toString());
624         }
625
626
627         else if ( peekch() == '.' ) return new Token( readch() );
628         else if ( peekch() == ';' ) return new Token( readch() );
629         else if ( peekch() == '\\') return new Token( readch() );
630         else if ( peekch() == ':' ) return new Token( readch() );
631         else if ( peekch() == '}' ) return new Token( readch() );
632         else if ( peekch() == '(' ) return new Token( readch() );
633         else if ( peekch() == ')' ) return new Token( readch() );
634         else if ( peekch() == '"' || peekch() == '\'') {
635             string(text, peekchar());
636             return new Token(Token.STRING, text.toString());
637         } else
638             die("unexpected char '" + (char)readch() + "'");
639     
640         case ST_TYPE:
641         if (peekch() == EOFCH) return EOF;
642         else if ( peekch() == '}' ) return new Token( readch() );
643         else if ( peekch() == ';' ) return new Token( readch() );
644         if (peekch() == '(') {
645             descriptor(text);
646             return new Token(Token.DESCRIPTOR, text.toString());
647         } else {
648             type(text);
649             return new Token(Token.TYPE, text.toString());
650         }
651
652
653         case ST_STRING:
654         if (peekch() == EOFCH) return EOF;
655         if (peekch() == ';') return new Token( readch() );
656         if ( peekch() == '"' || peekch() == '\'') {
657             string(text, peekchar());
658             return new Token(Token.STRING, text.toString());
659         }
660         while (true) {
661             text.append( readchar() );
662             if (peekch()==EOFCH || Character.isWhitespace(peekchar()) ||
663             peekch()==';')
664             return new Token(Token.STRING, text.toString());
665         }
666
667         case ST_ASM:
668         if (peekch() == EOFCH) return EOF;
669         if (peekch() == ';') return new Token( readch() );
670         if (peekch() == '}') return new Token( readch() );
671         if (peekch() == '{') return new Token( readch() );
672         if (peekch() == ':') die ("colon wihtout a label");
673         if ( peekch() == '"' || peekch() == '\'') {
674             string(text, peekchar());
675             return new Token(Token.TAG, text.toString());
676         }
677         while (true) {
678             text.append( readchar() );
679             if (peekch() == ':') {
680             readch();
681             return new Token(Token.LABEL, text.toString());
682             } if (Character.isWhitespace(peekchar())) {
683             skip_ws();
684             if (peekch() == ':') {
685                 readch();
686                 return new Token(Token.LABEL, text.toString());
687             } else
688                 return new Token(Token.TAG, text.toString());
689             }
690             if (peekch()==EOFCH || peekch()==';')
691             return new Token(Token.TAG, text.toString());
692         }
693
694
695         /*
696          * Unused (XXX)
697          *
698         case ST_ASM_NAME:
699         if ( peekch() == EOFCH) return EOF;
700         if (isIdChar(peekchar())) {
701             id(text);
702             return new Token(Token.NAME, text.toString());
703         }
704         if ( peekch() == ';' ) return new Token( readch() );
705         if ( peekch() == '.' ) return new Token( readch() );
706         if ( peekch() == ';' ) return new Token( readch() );
707         if ( peekch() == ':' ) return new Token( readch() );
708         die("unexpected char '" + (char)readch() + "'");
709
710         case ST_CONST:
711         if (peekch() == EOFCH) return EOF;
712         if (peekch() == ';') return new Token( readch() );
713         if (peekch() >= '0' && peekch() <= '9') {
714             int ret = readch() - '0';
715             while (peekch() >= '0' && peekch() <= '9')
716             ret = ret*10 + (readch() - '0');
717             return new Token(Token.INT, ret);
718         }
719         if ( peekch() == '"' || peekch() == '\'') {
720             string(text, peekchar());
721             return new Token(Token.STRING, text.toString());
722         }
723         die("unexpected char '" + (char)readch() + "'");
724         */

725
726         
727
728         }
729
730         throw new RuntimeException JavaDoc("internal error " + state);
731     } while (true);
732     }
733         
734     
735     // used externally
736
public Token match(int type) {
737     Token tok = read();
738     if (tok.type != type)
739         unexpected(tok);
740     return tok;
741     }
742
743
744     /* String parse_classname() {
745     Token tok = read();
746     StringBuffer ret = new StringBuffer();
747     if (tok.type == Token.NAME)
748         ret.append(tok.text);
749     else
750         unexpected(tok);
751
752     while (peek().type == '$') {
753         read();
754         ret.append('$');
755         ret.append( match(Token.NAME).text );
756     }
757     return ret.toString();
758     }*/

759
760
761
762     // used externally
763
public void term() {
764     if (la(1).type == Token.EOF || la(1).type == '}')
765         return;
766     match(';');
767     }
768         
769
770     // used externally
771
public String JavaDoc parse_name() {
772     String JavaDoc s = match(Token.NAME).text;
773     return s;
774     }
775
776     // used externally
777
public String JavaDoc parse_string() {
778     return match(Token.STRING).text;
779     }
780
781     // used externally
782
public Descriptor parse_descriptor() {
783     push(ST_TYPE);
784     String JavaDoc in = match(Token.DESCRIPTOR).text;
785     Descriptor d = new Descriptor(in);
786     pop();
787     return d;
788     }
789
790     // used externally
791
public Type parse_type() {
792     push(ST_TYPE);
793     String JavaDoc in = match(Token.TYPE).text;
794     Type t = new Type(in);
795     pop();
796     return t;
797     }
798
799     // used externally
800
public long parse_long() {
801     long l = match(Token.INT).l;
802     return l;
803     }
804
805     // used externally
806
public int parse_int() {
807     return (int) parse_long();
808     }
809
810     // used externally
811
public double parse_double() {
812     return match(Token.FLOAT).d;
813     }
814
815
816     /*
817      * Unused. (XXX)
818      *
819     float parse_float() {
820     return (float) parse_double();
821     }*/

822
823     // used externally
824
public int parse_flags(int ok) {
825     int ret = 0;
826     while (true) {
827         Token tok = peek();
828         if (tok.type != Token.NAME && tok.type != Token.TAG) return ret;
829
830         if (tok.text.equals("public") &&
831              ((Util.ACC_PUBLIC & ok) != 0))
832         ret |= Util.ACC_PUBLIC;
833         else if(tok.text.equals("private") &&
834             ((Util.ACC_PRIVATE & ok) != 0))
835         ret |= Util.ACC_PRIVATE;
836         else if(tok.text.equals("protected") &&
837             ((Util.ACC_PROTECTED & ok) != 0))
838         ret |= Util.ACC_PROTECTED;
839         else if(tok.text.equals("static") &&
840             ((Util.ACC_STATIC & ok) != 0))
841         ret |= Util.ACC_STATIC;
842         else if(tok.text.equals("final") &&
843             ((Util.ACC_FINAL & ok) != 0))
844         ret |= Util.ACC_FINAL;
845         else if(tok.text.equals("synchronized") &&
846             ((Util.ACC_SYNCHRONIZED & ok) != 0))
847         ret |= Util.ACC_SYNCHRONIZED;
848         else if(tok.text.equals("super") &&
849             ((Util.ACC_SUPER & ok) != 0))
850         ret |= Util.ACC_SUPER;
851         else if(tok.text.equals("native") &&
852             ((Util.ACC_NATIVE & ok) != 0))
853         ret |= Util.ACC_NATIVE;
854         else if(tok.text.equals("abstract") &&
855             ((Util.ACC_ABSTRACT & ok) != 0))
856         ret |= Util.ACC_ABSTRACT;
857         else if(tok.text.equals("strict") &&
858             ((Util.ACC_STRICT & ok) != 0))
859         ret |= Util.ACC_STRICT;
860         else if(tok.text.equals("volatile") &&
861             ((Util.ACC_VOLATILE & ok) != 0))
862         ret |= Util.ACC_VOLATILE;
863         else if(tok.text.equals("transient") &&
864             ((Util.ACC_TRANSIENT & ok) != 0))
865         ret |= Util.ACC_TRANSIENT;
866         else if(tok.text.equals("interface") &&
867             ((Util.ACC_INTERFACE & ok) != 0))
868         ret |= Util.ACC_INTERFACE;
869         else if (tok.text.equals("endflags")) {
870         read();
871         return ret;
872         } else
873         return ret;
874
875         read();
876     }
877     }
878
879
880     // used externally
881
public Descriptor parseOptDescriptor(String JavaDoc cname, String JavaDoc mname) throws ClassFileException {
882     if (la(1).type == ':') {
883         read();
884         return parse_descriptor();
885     }
886     ClassInfo cr = Jbet.loader.getClass(cname);
887     MethodInfo mi = cr.findMethod(mname);
888     if (mi == null) die
889         ("cannot determine type of " + cname + "." + mname);
890     return mi.descriptor;
891     }
892
893     // used externally
894
public Type parseOptType(String JavaDoc cname, String JavaDoc fname) throws ClassFileException {
895     if (la(1).type == ':') {
896         read();
897         return parse_type();
898     }
899     ClassInfo cr = Jbet.loader.getClass(cname);
900     FieldInfo mi = cr.findField(fname);
901     if (mi == null) die
902         ("cannot determine type of " + cname + "." + fname);
903     return mi.type;
904     }
905
906     // used externally
907
public String JavaDoc parse_optclassname (String JavaDoc default_class) {
908     if (default_class != null && peek().type != Token.NAME)
909         return default_class;
910     else
911         return parse_name();
912     }
913
914     private static final int PT_TYPE = 0x1;
915     private static final int PT_DESCRIPTOR = 0x2;
916     
917     // used externally
918
public Thing parse_thing (String JavaDoc defclass) {
919     return parse_thing (defclass, PT_DESCRIPTOR);
920     }
921     
922     // used externally
923
public Thing parse_thing(String JavaDoc defclass, int flags) {
924     String JavaDoc p_class = null;
925     String JavaDoc p_name = null;
926     Descriptor p_d = null;
927     Type p_t = null;
928
929     if (defclass != null && peek().type != Token.NAME)
930         p_class = defclass;
931     else
932         p_class = parse_name();
933     if (peek().type == '.') {
934         read();
935         p_name = parse_name();
936         if ( (flags & (PT_TYPE | PT_DESCRIPTOR)) == 0)
937         return new Thing (p_class, p_name, p_t, p_d);
938         if (peek().type == ':') {
939         read();
940         push(ST_TYPE);
941         if (peek().type == Token.TYPE && (flags & PT_TYPE) != 0 )
942             p_t = parse_type();
943         if (peek().type == Token.DESCRIPTOR &&
944             (flags & PT_DESCRIPTOR) != 0)
945             p_d = parse_descriptor();
946         else
947             unexpected(read());
948         pop();
949         }
950     }
951
952     return new Thing (p_class, p_name, p_t, p_d);
953     }
954
955     /**
956      * parse a class, method, or field, load it and return. this will
957      * throw an exception if it fails, so you can just call it and
958      * assume that it worked.
959      *
960      * @param defclass the default class
961      */

962     public Object JavaDoc getThing(String JavaDoc defclass) throws ClassFileException, ElementNotFoundException {
963     Thing t = parse_thing(defclass);
964     return Jbet.loader.getThing(t.cls, t.name, t.desc);
965     }
966
967     public MethodInfo getMethod(String JavaDoc defclass) throws ClassFileException, ElementNotFoundException {
968     Object JavaDoc thing = getThing(defclass);
969     if (thing instanceof MethodInfo)
970         return (MethodInfo) thing;
971     throw new ParseException ("expected a method");
972     }
973
974     public ClassInfo getClass(String JavaDoc defclass) throws ClassFileException, ElementNotFoundException {
975     String JavaDoc cname;
976     if (defclass != null && peek().type != Token.NAME)
977         cname = defclass;
978     else
979         cname = parse_name();
980     return Jbet.loader.getClass(cname);
981     }
982
983     /* a recursive helper for getClasses */
984     private void findClasses(Collection classes, String JavaDoc dirname, File dir,
985                  String JavaDoc packagePrefix, boolean sense) throws ClassFileException {
986     File [] files = dir.listFiles();
987     for (int i = 0; i < files.length; i++) {
988         if (files[i].isDirectory())
989         findClasses(classes,
990                 dirname + File.separator + files[i].getName(),
991                 files[i],
992                 packagePrefix + "/" + files[i].getName(), sense);
993         else if (files[i].getName().endsWith(".class")) {
994         Util.addOrRemove(classes, "@" + dirname + File.separator + files[i].getName(), sense);
995         }
996     }
997     }
998
999     /**
1000     * get a bunch of classes. supports @/foo/bar/* notation for all
1001     * the classes in a package
1002     **/

1003
1004    public ClassInfo [] getClasses() throws ClassFileException {
1005    Vector classes = new Vector();
1006    getClasses(classes);
1007    ClassInfo [] ret = new ClassInfo [ classes.size() ];
1008    classes.toArray(ret);
1009    return ret;
1010    }
1011    
1012    public void getClassNames (Collection classes) throws ClassFileException {
1013    getClassNames(classes, true);
1014    }
1015
1016    public void getClassNames (Collection classes, boolean sense) throws ClassFileException {
1017    while (peek().type == Token.NAME) {
1018        String JavaDoc name = parse_name();
1019        if (name.startsWith("@") && name.endsWith("/*")) {
1020        String JavaDoc dirname = name.substring(1, name.length()-2 );
1021        findClasses(classes,dirname, new File(dirname), "", sense);
1022        } else if (name.endsWith("/*")) {
1023        String JavaDoc packname = name.substring(0, name.length()-2);
1024        Jbet.loader.findPackageClasses(packname, classes, sense);
1025        } else if (name.equals("*")) {
1026        Jbet.loader.findPackageClasses("", classes, sense);
1027        } else
1028        classes.add( name );
1029    }
1030    if (peek().type == '\\') {
1031        read();
1032        getClassNames (classes, false);
1033    }
1034    }
1035
1036    public void getClasses (Collection classes) throws ClassFileException {
1037    getClasses(classes, Jbet.loader);
1038    }
1039
1040    public void getClasses (Collection classes,
1041                ClassFinder f) throws ClassFileException {
1042    Vector v = new Vector();
1043    getClassNames(v);
1044    for (int i = 0; i < v.size(); i++) {
1045        String JavaDoc name = (String JavaDoc) v.elementAt(i);
1046        classes.add( f.findClass(name) );
1047    }
1048    }
1049    
1050
1051    /**
1052     * parses a method or field, with a default class name.
1053     *
1054     * Using 2 lookahead here is safe. 3 would not be. I would
1055     * really like a rewindable multistate lexer, but that's a little
1056     * heavy for my meager requirements here
1057     *
1058     * @param def default class
1059     * @param opttype true if you want it to accept a type. */

1060    public Thing parse_element_with_default (String JavaDoc def, boolean opttype)
1061    throws Exception JavaDoc {
1062    
1063    String JavaDoc p_class = null;
1064    String JavaDoc p_name = null;
1065    String JavaDoc p_type;
1066    
1067    p_type = null;
1068    if ( this.la(1).type == Token.DEFAULT ||
1069         this.la(1).type == Token.DONOR ||
1070         ( this.la(1).type == Token.NAME &&
1071           ( this.la(2).type == '.' || this.la(2).type == '$' ))) {
1072        p_class = this.parse_name();//parse_classname(lexer);
1073
this.match('.');
1074    } else {
1075        if (def == null)
1076        this.die("you must provide a classname");
1077        else
1078        p_class = def;
1079    }
1080    p_name = this.parse_name();
1081    
1082    if (!opttype) return new Thing (p_class, p_name, null);
1083    
1084    if (this.la(1).type == ':') {
1085        this.read();
1086        this.push(ST_TYPE);
1087        p_type = this.match(Token.DESCRIPTOR).text;
1088        this.pop();
1089    }
1090
1091    return new Thing (p_class, p_name, p_type);
1092    }
1093
1094
1095
1096}
1097
Popular Tags