KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > SOFA > SOFAnode > Util > Builder


1 /* $Id: Builder.java,v 1.2 2004/05/20 14:23:53 bures Exp $ */
2
3 package SOFA.SOFAnode.Util;
4
5 import java.io.IOException JavaDoc;
6 import java.io.Reader JavaDoc;
7 import java.io.StringReader JavaDoc;
8
9 /**
10  * The class for building the automata from a given behavior protocol. A protocol is passed
11  * not into constructor, thus, one instance can be used for building any number of automata.
12  *
13  * @author Stanislav Visnovsky
14  * @version 1.0.0
15  *
16  * @see Machine
17  * @see checker
18 */

19 public class Builder {
20 /**
21  * next char for LL(1) parsing
22 */

23     private char next_char;
24
25 /**
26  * a reader which contains a behavior protocol to be parsed and built
27 */

28     private Reader JavaDoc source;
29
30 /**
31  * next token for LL(1) parsing
32 */

33     private String JavaDoc next_token;
34
35 /**
36  * flag for indicating the action token read
37 */

38     private boolean isTokenID;
39
40 /**
41  * Test for character to be a letter (case insensitive).
42  *
43  * @author Stanislav Visnovsky
44  * @version 1.0.0
45  *
46  * @param ch character to be tested
47  * @return result of the test
48  * @see Builder#nextToken
49 */

50     private boolean isLetter( char ch ) {
51         return ( ch>='a' && ch<='z' ) || ( ch>='A' && ch<='Z' );
52     }
53
54 /**
55  * Read the next token from the reader. In case of action token, indicate it by the isTokenID flag.
56  *
57  * @author Stanislav Visnovsky
58  * @version 1.5.1
59  *
60  * @return read token, or token EOF
61  * @throws SyntaxErrorException in case of badly formed protocols
62  * @see Builder#isTokenID
63 */

64     private String JavaDoc nextToken() throws SyntaxErrorException, IOException JavaDoc {
65     String JavaDoc result;
66         isTokenID = false;
67         if( !source.ready() ) {
68             Debug.println( 2, "EOF" );
69             return "EOF";
70         }
71         while( next_char == ' ' ) // skip whitespaces
72
if( source.ready() ) next_char = (char)source.read();
73             else {
74                 Debug.println( 2, "EOF" );
75                 return "EOF";
76             }
77         switch( next_char ) {
78             case (char)-1: {
79                 Debug.println( 2, "EOF" );
80                 return "EOF";
81                 }
82             case '|':
83                 next_char = (char)source.read();
84                 if( next_char == '|') {
85                     next_char = (char)source.read();
86                     Debug.print( 2, "||");
87                     return "||";
88                 } else {
89                     Debug.print( 2, "|");
90                     return "|";
91                 }
92             case '&':
93                 next_char = (char)source.read();
94                 Debug.print(2,"&");
95                 return "&";
96             case '@':
97                 next_char = (char)source.read();
98                 Debug.print(2,"@");
99                 return "@";
100             case '.':
101                 next_char = (char)source.read();
102                 Debug.print(2,".");
103                 return ".";
104             case '*':
105                 next_char = (char)source.read();
106                 Debug.print(2,"*");
107                 return "*";
108             case '+':
109                 next_char = (char)source.read();
110                 Debug.println(2,"+");
111                 return "+";
112             case ';':
113                 next_char = (char)source.read();
114                 Debug.print(2,";");
115                 return ";";
116             case ',':
117                 next_char = (char)source.read();
118                 Debug.print(2,",");
119                 return ",";
120             case '\\':
121                 next_char = (char)source.read();
122                 Debug.print(2,"\\");
123                 return "\\";
124             case '{':
125                 next_char = (char)source.read();
126                 Debug.print(2,"{");
127                 return "{";
128             case '}':
129                 next_char = (char)source.read();
130                 Debug.print(2,"}");
131                 return "}";
132             case '(':
133                 next_char = (char)source.read();
134                 Debug.print(2,"(");
135                 return "(";
136             case ')':
137                 next_char = (char)source.read();
138                 Debug.print(2,")");
139                 return ")";
140         case '[':
141         result = "[";
142         next_char = (char)source.read();
143         while( next_char != ']' ) {
144             result += next_char;
145             next_char = (char)source.read();
146         }
147         result += next_char;
148         next_char = (char)source.read();
149         isTokenID = true;
150         Debug.print(2, result);
151         return result;
152             default:
153                 if( isLetter(next_char) || next_char == '?' ||
154                     next_char == '!' || next_char == '<' || next_char == '#' ) {
155                     result = "";
156                     if( next_char == '!' || next_char == '?' || next_char == '#') {
157                          result = result + next_char;
158                          next_char = (char)source.read();
159                     }
160                     if( next_char == '<' ) {
161                         do {
162                            result = result + next_char;
163                            next_char = (char)source.read();
164                         } while( next_char != '>' );
165                         result = result + next_char;
166                         next_char = (char)source.read();
167                     } else {
168                         while( isLetter(next_char) ) {
169                         result = result + next_char;
170                         next_char = (char)source.read();
171                         }
172                     }
173                     if( next_char != '.' )
174             {
175             if( result.equals( "NULL" ) )
176             {
177                 isTokenID = true;
178                 Debug.print(2,result);
179                 return result;
180             }
181             throw new SyntaxErrorException("invalide event name: dot delimiter expected in event name, found "+next_char+" after "+result);
182                     }
183             else result = result + next_char;
184                     next_char = (char)source.read();
185                     while( isLetter(next_char) ) {
186                        result = result + next_char;
187                        next_char = (char)source.read();
188                     }
189                     if( next_char == '^' || next_char == '$' || next_char == '~' ) {
190                             result = result + next_char;
191                             next_char = (char)source.read();
192                     }
193                     isTokenID = true;
194                     Debug.print(2,result);
195                     return result;
196                 }
197                 throw new SyntaxErrorException("Unexpected literal with code "+ (int)next_char);
198          }
199     }
200
201     public void fillIdentifiers(String JavaDoc prot) {
202     ActionToken a;
203         try {
204             boolean incomposition = false;
205         source = new StringReader JavaDoc(prot);
206             next_char = (char)source.read();
207             next_token = nextToken();
208         while( next_token != "EOF" ) {
209         if( isTokenID && !next_token.equals("NULL") && !next_token.startsWith("["))
210         if( next_token.startsWith( "?" ) || next_token.startsWith( "!" ) ||next_token.startsWith( "#" ) ) {
211         // this is action /action token
212
if( next_token.endsWith( "^" ) || next_token.endsWith( "$" ) || next_token.endsWith( "~" ) ) {
213             // this is action token
214
Debug.println(3, "CollectList: action token");
215             a = new ActionToken( next_token );
216             EdgeFactory.getActionTokenIdx(a);
217         } else {
218             Debug.println(3, "CollectList: action token without");
219             // this is just action
220
a = new ActionToken( next_token+"^" );
221             EdgeFactory.getActionTokenIdx(a);
222             a = new ActionToken( next_token+"$" ).toInverseActionToken();
223             EdgeFactory.getActionTokenIdx(a);
224         }
225         } else {
226         // this is event / or event name
227
if( next_token.endsWith( "^" ) || next_token.endsWith( "$" ) || next_token.endsWith( "~" ) ) {
228             Debug.println(3, "CollectList: adding event");
229             // this is event
230
a = new ActionToken( "?"+next_token );
231             EdgeFactory.getActionTokenIdx(a);
232             a = new ActionToken( "!"+next_token );
233             EdgeFactory.getActionTokenIdx(a);
234             if( incomposition ) { // this is list for composition
235
a = new ActionToken( "#"+next_token );
236               EdgeFactory.getActionTokenIdx(a);
237             }
238         } else {
239             Debug.println(3, "CollectList: adding event name");
240             // this is event name
241
a = new ActionToken( "?"+next_token+"^" );
242             EdgeFactory.getActionTokenIdx(a);
243             a = new ActionToken( "?"+next_token+"$" );
244             EdgeFactory.getActionTokenIdx(a);
245             a = new ActionToken( "!"+next_token+"^" );
246             EdgeFactory.getActionTokenIdx(a);
247             a = new ActionToken( "!"+next_token+"$" );
248             EdgeFactory.getActionTokenIdx(a);
249             if( incomposition ) { // this is list for composition
250
a = new ActionToken( "#"+next_token+"^" );
251               EdgeFactory.getActionTokenIdx(a);
252               a = new ActionToken( "#"+next_token+"$" );
253               EdgeFactory.getActionTokenIdx(a);
254             }
255         }
256         }
257         if( next_token == "&" ) incomposition = !incomposition;
258         next_token = nextToken();
259         }
260         Debug.println( 1,"Filling identifiers: finished" );
261         } catch( Exception JavaDoc e ) { }
262     
263     }
264
265     public static void fillOneName(String JavaDoc name, boolean includetau) {
266     ActionToken a;
267         try {
268         if( name.startsWith( "?" ) || name.startsWith( "!" ) ||name.startsWith( "#" ) ) {
269         // this is action /action token
270
if( name.endsWith( "^" ) || name.endsWith( "$" ) || name.endsWith( "~" ) ) {
271             // this is action token
272
Debug.println(3, "fillOneName: action token");
273             a = new ActionToken( name );
274             EdgeFactory.getActionTokenIdx(a);
275         } else {
276             Debug.println(3, "fillOneName: action token without");
277             // this is just action
278
a = new ActionToken( name+"^" );
279             EdgeFactory.getActionTokenIdx(a);
280             a = new ActionToken( name+"$" ).toInverseActionToken();
281             EdgeFactory.getActionTokenIdx(a);
282         }
283         } else {
284         // this is event / or event name
285
if( name.endsWith( "^" ) || name.endsWith( "$" ) || name.endsWith( "~" ) ) {
286             Debug.println(3, "fillOneName: adding event");
287             // this is event
288
a = new ActionToken( "?"+name );
289             EdgeFactory.getActionTokenIdx(a);
290             a = new ActionToken( "!"+name );
291             EdgeFactory.getActionTokenIdx(a);
292             if( includetau ) { // this is list for composition
293
a = new ActionToken( "#"+name );
294               EdgeFactory.getActionTokenIdx(a);
295             }
296         } else {
297             Debug.println(3, "fillOneName: adding event name");
298             // this is event name
299
a = new ActionToken( "?"+name+"^" );
300             EdgeFactory.getActionTokenIdx(a);
301             a = new ActionToken( "?"+name+"$" );
302             EdgeFactory.getActionTokenIdx(a);
303             a = new ActionToken( "!"+name+"^" );
304             EdgeFactory.getActionTokenIdx(a);
305             a = new ActionToken( "!"+name+"$" );
306             EdgeFactory.getActionTokenIdx(a);
307             if( includetau ) { // this is list for composition
308
a = new ActionToken( "#"+name+"^" );
309               EdgeFactory.getActionTokenIdx(a);
310               a = new ActionToken( "#"+name+"$" );
311               EdgeFactory.getActionTokenIdx(a);
312             }
313         }
314         }
315         } catch( Exception JavaDoc e ) { }
316     
317     }
318
319 /**
320  * Builds protocol for + operator.
321  *
322  * @author Stanislav Visnovsky
323  * @version 2.0.0
324  *
325  * @return built protocol
326  * @throws SyntaxErrorException in case of badly formed protocols
327  * @throws IOException in case of unexpected end of reader
328  *
329  * @see Builder#sequence
330  * @see ProtocolAlternative
331 */

332     private Protocol alternative() throws SyntaxErrorException, IOException JavaDoc {
333         Protocol result = sequence();
334         while( next_token == "+" ) {
335             next_token = nextToken();
336             Protocol m = sequence();
337             result = new ProtocolAlternative( result, m );
338         }
339         return result;
340     }
341
342 /**
343  * Builds protocol for ; operator.
344  *
345  * @author Stanislav Visnovsky
346  * @version 2.0.0
347  *
348  * @return built automaton
349  * @throws SyntaxErrorException in case of badly formed protocols
350  * @throws IOException in case of unexpected end of reader
351  *
352  * @see Builder#andparallel
353  * @see ProtocolSequence
354 */

355     private Protocol sequence() throws SyntaxErrorException, IOException JavaDoc {
356         Protocol result = andparallel();
357
358         while( next_token == ";" ) {
359         next_token = nextToken();
360             Protocol m = andparallel();
361         result = new ProtocolSequence( result, m );
362         }
363     
364         return result;
365     }
366
367 /**
368  * Builds protocol for | operator.
369  *
370  * @author Stanislav Visnovsky
371  * @version 2.0.0
372  *
373  * @return built protocol
374  * @throws SyntaxErrorException in case of badly formed protocols
375  * @throws IOException in case of unexpected end of reader
376  *
377  * @see ProtocolParallel
378  * @see Builder#orparallel
379  */

380     private Protocol andparallel() throws SyntaxErrorException, IOException JavaDoc {
381         Protocol result = orparallel();
382         while( next_token == "|" ) {
383             next_token = nextToken();
384             Protocol m = orparallel();
385             result = new ProtocolParallel( result, m );
386         }
387         return result;
388     }
389
390 /**
391  * Builds protocol for || operator.
392  *
393  * @author Stanislav Visnovsky
394  * @version 2.0.0
395  *
396  * @return built protocol
397  * @throws SyntaxErrorException in case of badly formed protocols
398  * @throws IOException in case of unexpected end of reader
399  *
400  * @see ProtocolOrParallel
401  * @see Builder#term
402  */

403     private Protocol orparallel() throws SyntaxErrorException, IOException JavaDoc {
404         Protocol result = term();
405         while( next_token == "||" ) {
406             next_token = nextToken();
407             Protocol m = term();
408         result = new ProtocolOrParallel(result,m);
409         }
410         return result;
411     }
412
413 /**
414  * Parse a list of comma-separaded ids. Requires that all identifiers to
415  * be already in EdgeFactory.ActionTokens
416  *
417  * @author Stanislav Visnovsky
418  * @version 2.0.0
419  *
420  * @return read list of ids
421  * @param endmark a string to mark the end of the list
422  * @throws SyntaxErrorException in case of badly formed protocols
423  * @throws IOException in case of unexpected end of reader
424  *
425  * @see Builder#nextToken
426  * @see Builder#composition
427  * @see Builder#adjustment
428  * @see EdgeFactory#ActionTokens
429  */

430     private ActionTokenArray collectList( String JavaDoc endmark ) throws SyntaxErrorException, IOException JavaDoc {
431         ActionTokenArray result = new ActionTokenArray();
432         while( isTokenID ) {
433         if( next_token.startsWith( "?" ) || next_token.startsWith( "!" ) ||next_token.startsWith( "#" ) ) {
434         // this is action /action token
435
if( next_token.endsWith( "^" ) || next_token.endsWith( "$" ) || next_token.endsWith( "~" ) ) {
436             // this is action token
437
Debug.println(3, "CollectList: action token");
438             ActionToken a = new ActionToken( next_token );
439             result.tokens[EdgeFactory.getActionTokenIdx(a)]=true;
440         } else {
441             Debug.println(3, "CollectList: action token without");
442             // this is just action
443
ActionToken a = new ActionToken( next_token+"^" );
444             result.tokens[EdgeFactory.getActionTokenIdx(a)]=true;
445             a = new ActionToken( next_token+"$" ).toInverseActionToken();
446             result.tokens[EdgeFactory.getActionTokenIdx(a)]=true;
447         }
448         } else {
449         // this is event / or event name
450
if( next_token.endsWith( "^" ) || next_token.endsWith( "$" ) || next_token.endsWith( "~" ) ) {
451             Debug.println(3, "CollectList: adding event");
452             // this is event
453
ActionToken a = new ActionToken( "?"+next_token );
454             result.tokens[EdgeFactory.getActionTokenIdx(a)]=true;
455             a = new ActionToken( "!"+next_token );
456             result.tokens[EdgeFactory.getActionTokenIdx(a)]=true;
457             if( endmark == "&" ) { // this is list for composition
458
a = new ActionToken( "#"+next_token );
459               result.tokens[EdgeFactory.getActionTokenIdx(a)]=true;
460             }
461         } else {
462             Debug.println(3, "CollectList: adding event name");
463             // this is event name
464
ActionToken a = new ActionToken( "?"+next_token+"^" );
465             result.tokens[EdgeFactory.getActionTokenIdx(a)]=true;
466             a = new ActionToken( "?"+next_token+"$" );
467             result.tokens[EdgeFactory.getActionTokenIdx(a)]=true;
468             a = new ActionToken( "!"+next_token+"^" );
469             result.tokens[EdgeFactory.getActionTokenIdx(a)]=true;
470             a = new ActionToken( "!"+next_token+"$" );
471             result.tokens[EdgeFactory.getActionTokenIdx(a)]=true;
472             if( endmark == "&" ) { // this is list for composition
473
a = new ActionToken( "#"+next_token+"^" );
474               result.tokens[EdgeFactory.getActionTokenIdx(a)]=true;
475               a = new ActionToken( "#"+next_token+"$" );
476               result.tokens[EdgeFactory.getActionTokenIdx(a)]=true;
477             }
478         }
479         }
480             next_token = nextToken();
481             if( next_token == endmark ) {
482                 Debug.println( 2,"End mark reached " );
483                 next_token = nextToken();
484                 return result;
485             }
486             if( next_token.compareTo( "," ) != 0) throw new SyntaxErrorException("Comma expected in list");
487             else next_token = nextToken();
488         }
489         if( next_token == endmark ) {
490             Debug.println(2, "End mark reached" );
491             next_token = nextToken();
492             return result;
493         }
494         else throw new SyntaxErrorException("List syntax error");
495     }
496
497 /**
498  * Builds automaton for restriction operator by invoking the Restrict() operation.
499  *
500  * @author Stanislav Visnovsky
501  * @version 1.0.0
502  *
503  * @return built automaton
504  * @throws SyntaxErrorException in case of badly formed protocols
505  * @throws IOException in case of unexpected end of reader
506  *
507  * @see Machine#Restrict
508  * @see Builder#collectList
509  */

510     private Protocol restriction() throws SyntaxErrorException, IOException JavaDoc {
511         Protocol result = alternative();
512         while( next_token == "\\" ) {
513             Debug.println( 2,"Restriction found");
514             next_token = nextToken();
515             if( next_token != "(" ) throw new SyntaxErrorException("Restriction list expected");
516             next_token = nextToken();
517             ActionTokenArray sync = collectList( ")" );
518             Debug.println( 2,"Restriction action tokens: "+sync.toList() );
519             
520         result.Restrict( new ActionTokenArray(sync ) );
521         
522         result = new ProtocolRestriction( result, sync );
523         }
524         return result;
525     }
526
527 /**
528  * Builds automaton for composition operator by invoking the createComposition.
529  *
530  * @author Stanislav Visnovsky
531  * @version 1.0.0
532  *
533  * @return built automaton
534  * @throws SyntaxErrorException in case of badly formed protocols
535  * @throws IOException in case of unexpected end of reader
536  *
537  * @see Builder#alternative
538  * @see Builder#createComposition
539  * @see Machine
540  * @see stateImpl
541  */

542     private Protocol composition() throws SyntaxErrorException, IOException JavaDoc {
543         Protocol result = restriction();
544         while( next_token == "&" ) {
545             Debug.println(2, "Composition found" );
546             next_token = nextToken();
547             ActionTokenArray sync = collectList( "&" );
548             Debug.println( 2,"Composition action tokens: "+sync.toList() );
549             Protocol m = restriction();
550             result = new ProtocolComposition( result, m, sync );
551         }
552         return result;
553     }
554
555 /**
556  * Builds protocol for adjustment operator.
557  *
558  * @author Stanislav Visnovsky
559  * @version 2.0.0
560  *
561  * @return built protocol
562  * @throws SyntaxErrorException in case of badly formed protocols
563  * @throws IOException in case of unexpected end of reader
564  *
565  * @see Builder#composition
566  * @see ProtocolAdjustment
567  * @see collectList
568  */

569     private Protocol adjustment() throws SyntaxErrorException, IOException JavaDoc {
570         Protocol result = composition();
571         while( next_token == "@" ) {
572             Debug.println( 2,"Adjustment found" );
573             next_token = nextToken();
574             ActionTokenArray sync = collectList( "@" );
575             Debug.println( 2,"Adjustment action tokens: "+sync.toList() );
576             Protocol m = composition();
577             result = new ProtocolAdjustment( result, m, new ActionTokenArray(sync) );
578         }
579         return result;
580     }
581
582 /**
583  * Builds the automata for unary operator *.
584  *
585  * @author Stanislav Visnovsky
586  * @version 1.0.0
587  *
588  * @return built automaton
589  * @throws SyntaxErrorException in case of badly formed protocols
590  * @throws IOException in case of unexpected end of reader
591  *
592  * @see Builder#factor
593  * @see Machine
594  * @see stateImpl
595  * @see edgeSimple
596 */

597     private Protocol term() throws SyntaxErrorException, IOException JavaDoc {
598         Protocol result = factor();
599         if( next_token == "*" ) {
600             next_token = nextToken();
601         result = new ProtocolRepetition( result );
602         }
603         return result;
604     }
605
606 /**
607  * Builds the basic automata for action tokens and NULL. Also, parentheses are handled here.
608  *
609  * @author Stanislav Visnovsky
610  * @version 1.0.0
611  *
612  * @return built automaton
613  * @throws SyntaxErrorException in case of badly formed protocols
614  * @throws IOException in case of unexpected end of reader
615  *
616  * @see Builder#alternative
617  * @see Machine
618  * @see stateImpl
619  * @see edgeSimple
620 */

621     private Protocol factor() throws SyntaxErrorException, IOException JavaDoc {
622         Protocol result;
623     if( next_token.equals("NULL") )
624     {
625         result = new ProtocolToken( new ActionToken("NULL") );
626             next_token = nextToken();
627     } else
628         if( next_token == "(" ) {
629             next_token = nextToken();
630             result = adjustment();
631             if( next_token != ")" ) { throw new SyntaxErrorException(") expected"); }
632             next_token = nextToken();
633         } else
634         if( next_token.equals("EOF") ) {
635             result = null;
636         } else { // it has to be an action token or abbreviation
637
if( !isTokenID ) throw new SyntaxErrorException("identifier expected, last token "+next_token);
638         String JavaDoc event = next_token;
639             next_token = nextToken();
640         if( next_token == "{" ) {
641             // nested call abbreviation
642
next_token = nextToken();
643             Protocol pom = alternative();
644
645             if( next_token != "}" ) throw new SyntaxErrorException("} expected");
646                     next_token = nextToken();
647
648             if( !event.startsWith( "?" ) ) event = "?" + event;
649             ActionToken start = new ActionToken(event+"^");
650
651                 ActionToken stop = start.toInverseActionToken();
652
653                 stop = new ActionToken( stop.name.substring(0,stop.name.length()-1) + "$" );
654
655         pom = new ProtocolSequence( new ProtocolToken( start ), pom );
656         pom = new ProtocolSequence( pom, new ProtocolToken( stop ) );
657         
658         Debug.println(3, "Nested call abbreviation:");
659         ((Printer)pom).Print(3);
660         
661             result = pom;
662         } else {
663     // action token or simple call abbrevation
664
ActionToken a = new ActionToken( event );
665         if( a.isSimpleCall() ) { // simple call abbreviation
666
ActionToken start = new ActionToken( a.name+'^') ;
667                     ActionToken stop = new ActionToken( a.name+'$').toInverseActionToken();
668             result = new ProtocolSequence( new ProtocolToken( start ), new ProtocolToken( stop ) );
669         } else { // action token
670
result = new ProtocolToken( a );
671         }
672         }
673         }
674         return result;
675     }
676
677 /**
678  * The main entry point for building the automaton for a behavior protocol. Using all
679  * private methods of this class, this method takes a string as the argument and then it
680  * builds the automton by invoking Build for reader argument
681  *
682  * @author Stanislav Visnovsky
683  * @version 1.0.0
684  *
685  * @param protocol a reader containing a protocol to be build
686  * @return built automaton
687  * @throws SyntaxErrorException in case of badly formed protocols
688  * @throws IOException in case of unexpected end of reader
689 */

690     public Protocol Build( String JavaDoc protocol ) throws SyntaxErrorException {
691         Debug.println( 1,"Protocol Build: start");
692         try {
693             source = new StringReader JavaDoc(protocol);
694             next_char = (char)source.read();
695             next_token = nextToken();
696             Protocol m = adjustment();
697         Debug.println( 1,"Protocol Build: finished" );
698         ((Printer)m).Print( 2 );
699             return m;
700         } catch( IOException JavaDoc e ) { return null; }
701     }
702
703 }
Popular Tags