Source code: com/trapezium/vrml/grammar/PROTORule.java
1 /*
2 * @(#)PROTORule.java
3 *
4 * Copyright (c) 1998 by Trapezium Development LLC. All Rights Reserved.
5 *
6 * The information in this file is the property of Trapezium Development LLC
7 * and may be used only in accordance with the terms of the license granted
8 * by Trapezium.
9 *
10 */
11 package com.trapezium.vrml.grammar;
12
13 import com.trapezium.parse.TokenEnumerator;
14 import com.trapezium.vrml.VrmlElement;
15 import com.trapezium.vrml.node.PROTO;
16 import com.trapezium.vrml.node.PROTObase;
17 import com.trapezium.vrml.Scene;
18 import com.trapezium.vrml.LeftBrace;
19 import com.trapezium.vrml.LeftBracket;
20 import com.trapezium.vrml.RightBrace;
21 import com.trapezium.vrml.RightBracket;
22 import com.trapezium.vrml.NodeTypeId;
23
24 /**
25 * Creates the scene graph component for a PROTO declaration.
26 *
27 * Grammar handled by "Build" method:
28 * <PRE>
29 * proto ::=
30 * PROTO nodeTypeId [ interfaceDeclarations ] { protoBody } ;
31 *
32 * interfaceDeclarations ::=
33 * interfaceDeclaration |
34 * interfaceDeclaration interfaceDeclarations |
35 * empty ;
36 *
37 * protoBody ::=
38 * protoStatements node statements ;
39 *
40 * protoStatements ::=
41 * protoStatement |
42 * protoStatement protoStatements |
43 * empty ;
44 * </PRE>
45 * Note: the implementation of the "protoBody" portion of above grammar
46 * is done through the SceneRule, followed by a check that the body
47 * consists of at least one node. This check (and possible error mark)
48 * is done by the "setBuiltInNodeType" method.
49 *
50 * @author Johannes N. Johannsen
51 * @version 1.1, 6 Jan 1998
52 *
53 * @since 1.0
54 */
55 public class PROTORule {
56 int level = 0;
57 InterfaceDeclarationRule interfaceDeclarationRule;
58
59 /** Class constructor */
60 PROTORule( NodeRule nodeRule ) {
61 interfaceDeclarationRule = new InterfaceDeclarationRule( nodeRule );
62 }
63
64 void Build( int tokenOffset, TokenEnumerator v, Scene scene, VrmlElement parent ) {
65 GrammarRule.Enter( "PROTORule.Build" );
66 level++;
67 // at this point, tok is known to be "PROTO", get next one
68 int originalTokenOffset = tokenOffset;
69 tokenOffset = v.getNextToken();
70 if ( tokenOffset != -1 ) {
71 PROTO p = new PROTO( originalTokenOffset );
72 NodeTypeId ntid = new NodeTypeId( tokenOffset, v );
73 p.addChild( ntid );
74 tokenOffset = v.getNextToken();
75 boolean leftBracketMissing = false;
76 if ( !v.sameAs( tokenOffset, "[" )) {
77 // if there was no left bracket, assume it was missing,
78 // continue as if it was there
79 p.addChild( new LeftBracket( tokenOffset, v ));
80 leftBracketMissing = true;
81 }
82 while ( true ) {
83 if ( !leftBracketMissing ) {
84 tokenOffset = v.getNextToken();
85 }
86 leftBracketMissing = false;
87 if ( tokenOffset == -1 ) {
88 p.setError( "Did not find matching right bracket" );
89 break;
90 } else if ( v.sameAs( tokenOffset, "]" )) {
91 break;
92 }
93 interfaceDeclarationRule.Build( tokenOffset, v, scene, p );
94 }
95 if ( !v.sameAs( tokenOffset, "]" )) {
96 p.addChild( new RightBracket( tokenOffset, v ));
97 }
98 Scene s = new Scene();
99 s.setErrorSummary( scene.getErrorSummary() );
100 s.setTokenEnumerator( v );
101 s.setPROTOparent( p );
102 p.addChild( s );
103
104 p.addChild( new LeftBrace( v.getNextToken(), v ));
105
106 parent.addChild( p );
107
108 // Build the scene associated with the PROTO
109 VRML97parser parser = VRML97parser.singleton;
110 parser.Build( v, s, s, "}" );
111
112 if ( v.getCurrentTokenOffset() != -1 ) {
113 p.addChild( new RightBrace( v.getCurrentTokenOffset(), v ));
114 }
115 p.setLastTokenOffset( v.getCurrentTokenOffset() );
116
117 // Set the type of the PROTO node based on the first node defined in the scene,
118 // then register the prototype with the scene
119 p.setBuiltInNodeType( s.getFirstNodeType() );
120 PROTObase pb = scene.getPROTO( p.getId() );
121 if ( pb != null ) {
122 ntid.setError( "Warning, there is another PROTO with this name" );
123 }
124
125 // Register the PROTO declaration with the scene.
126 scene.registerPROTO( p );
127
128 // Look for unused fields from the PROTO interface declaration
129 p.checkInUse();
130 if ( level == ( Table7.PROTONestingLimit + 1 )) {
131 p.setError( "Nonconformance, base profile PROTO nesting limit " + Table7.PROTONestingLimit + " exceeded here" );
132 }
133 } else {
134 parent.setError( "Unexpected end of file" );
135 }
136 level--;
137 GrammarRule.Exit( "PROTORule.Build" );
138 }
139 }