Source Code Cross Referenced for Parser.java in  » Science » Cougaar12_4 » org » cougaar » core » adaptivity » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Science » Cougaar12_4 » org.cougaar.core.adaptivity 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /* 
002:         * <copyright>
003:         *  
004:         *  Copyright 2002-2004 BBNT Solutions, LLC
005:         *  under sponsorship of the Defense Advanced Research Projects
006:         *  Agency (DARPA).
007:         * 
008:         *  You can redistribute this software and/or modify it under the
009:         *  terms of the Cougaar Open Source License as published on the
010:         *  Cougaar Open Source Website (www.cougaar.org).
011:         * 
012:         *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013:         *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014:         *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015:         *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016:         *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017:         *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018:         *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019:         *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020:         *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021:         *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022:         *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023:         *  
024:         * </copyright>
025:         */
026:
027:        package org.cougaar.core.adaptivity;
028:
029:        import java.io.IOException;
030:        import java.io.Reader;
031:        import java.io.StreamTokenizer;
032:        import java.util.ArrayList;
033:        import java.util.List;
034:
035:        import org.cougaar.core.service.LoggingService;
036:
037:        /**
038:         * Parser for plays to be stored in a Playbook. The grammar is
039:         * straightforward with the exception of ranges and range lists.
040:         * <h3>Basic Syntax</h3>
041:         * <p>Each play consists of an if clause (predicate) and one or more
042:         * constraint phrases. These are all separated by colons and
043:         * terminated with a semi-colon. For example:</p>
044:         * <pre>&lt;if clause&gt;:&lt;constraint&gt;:...&lt;constraint&gt;;</pre><p>
045:         * The &lt;if clause&gt; is an expression involving {@link Condition}s and
046:         * constants that must evaluate to true or false. A constraint
047:         * consists of an {@link OperatingMode} following by a
048:         * ConstraintOperator and a range list and signifies that the
049:         * OperatingMode will be constrained so as to satisfy the relation
050:         * specified by the operator to the range list. For example:</p>
051:         * <pre>
052:         * FooPlugin.MODE &lt; 5;
053:         * FooPlugin.MODE in {1 to 7};
054:         * FooPlugin.SPEED = "FAST";</pre><p>
055:         * Note that both relational and range operators (==, not it, etc.) as
056:         * well as assignment may be used. Assignment explicitly specifies the
057:         * allowed values. Relational and range operators implicitly specify
058:         * the allowed values by specifying the test that any such value must
059:         * satisfy. The operators =, ==, and in are all equivalent as are !=
060:         * and not in. The other relational operators are usually used with
061:         * single valued range lists (constants).
062:         * <h3>Comments</h3><p>
063:         * Comments are ignored by the parser. Both slash-slash and slash-star
064:         * comments are recognized. The former beging with two adjacent
065:         * slashes and terminate at the end of line. The latter terminate with
066:         * a star-slash sequence.</p>
067:         * <h3>Numeric Constants</h3><p>
068:         * Numeric constants are interpreted as floating point numbers
069:         * (doubles). When necessary, numbers will be automatically cast to integers or
070:         * longs. A consequence of this is that plays may not use the full
071:         * precision offered by longs (64 bits) and are restricted to the 56
072:         * bits of precision in a double.
073:         * <h3>Ranges</h3><p>
074:         * A range is written as two numbers separated by the keyword "to" or
075:         * "thru". The former excludes the end point and the latter includes
076:         * the end point. A point range (a range having exactly one value) may
077:         * be written as a single number; 7 is equivalent to 7 thru 7. 7 to 7,
078:         * on the other hand, is an empty range; it allows no values.
079:         * <h3>Range Lists</h3><p>
080:         * A range list is a sequence of ranges enclosed in braces. The
081:         * elements of a range list may be separated by commas, but they are
082:         * not required; white space is sufficient. A range
083:         * list consisting of exactly one range my omit the braces.
084:         * Consequently, a numeric constant is also a range list. Range lists
085:         * frequently have elements that are point ranges and express list of
086:         * descrete values rather than a continuum. Range lists
087:         * may appear only as the right-hand operand of relational operators
088:         * (see below). Numeric constants may appear in arithmetic expressions.
089:         * to the written value. In general the context makes it clear which
090:         * should be used, but for example:</p><pre>
091:         * Foo &lt; {11 to 20, 25 thru 30, 1 to 3};</pre><p>
092:         * is true if Foo is less than 1 (the minimum of the ranges). This
093:         * characteristic is an artifact of the parser and probably
094:         * insignificant to the playbook writer.</p><p>
095:         * As implied above, a range list consists of one or more ranges
096:         * enclosed in braces. The comma between the ranges is optional (white
097:         * space is sufficient). The braces are also optional if the list has
098:         * a single range. Each range consists of either one number or string
099:         * or two numbers or strings separated by either "to" or "thru". "To"
100:         * signifies a range that does not include the end point whereas
101:         * "thru" signifies a range that does include the end point. If the
102:         * number is floating point, only the exact value given by the end
103:         * point is excluded. The next smaller value that can be represented
104:         * is always included. This characteristic can be used to insure there
105:         * are no gaps in the coverage of a series of predicates. For
106:         * example:</p><pre>
107:         * x in {1 to 3, 5 to 10}:...;
108:         * x in {3 to 5}:...;
109:         * x &gt;= 10:...;</pre><p>insures that exactly one of the predicates
110:         * is true for any
111:         * value of x from 1 to infinity. There is no value of x that can fall
112:         * into a crack in the vicinity of 3 or 5 or 10 nor is there any value of x
113:         * in those same regions that can cause two predicates to
114:         * fire.</p><p>Numbers are parsed as doubles and coerced to other
115:         * numeric typs as needed. This means that long values cannot be
116:         * written with their entire range. (Doubles can exactly represent
117:         * only 56 bits of precision.)</p>
118:         * <h3>Strings</h3><p>Strings are used as constants (range limits),
119:         * Condition names and OperatingMode names. The interpretation depends
120:         * on context (see below). Strings do not need to be quoted unless
121:         * they contain characters (such as spaces) that have syntactic
122:         * meaning to the parser. In particular, strings need not be quoted
123:         * when they contain . (period) and [] (brackets). All other
124:         * punctuation and special characters should be quoted.</p><p>
125:         * String constants can be used in range lists and arithmetic
126:         * expressions using the + operator. Strings cannot be used in other
127:         * arithmetic expressions. String comparisons are usually
128:         * confined to equality and inequality tests, but the other operators
129:         * have a defined meaning (alphabetic comparison using the default
130:         * collation sequence). String ranges are rare, but if used, have a
131:         * slightly different meaning when "to" ranges are specified because
132:         * the highest value included in a "to" range would be infinitely
133:         * long. For example, the last string in the range "bar" to "foo"
134:         * would be "fon\uffff\uffff\uffff\uffff...". It is hard to conceive of
135:         * a use for a "to" range involving strings, so the infinite string is
136:         * truncated after the first "\uffff".</p>
137:         * Strings that name Conditions <em>can</em> be used in arithmetic
138:         * expressions if the named Condition has a numeric value. If the
139:         * named Condition has a String value, then only the + operator is
140:         * allowed.
141:         * <h3>If Clause Operators</h3>
142:         * <h4>Arithmetic Operators (+, -, *, /)</h4><p>
143:         * These have their standard meanings. The parser treats these with
144:         * standard precedence so parentheses are needed in the usual places.
145:         * When in doubt, parenthesize. There is no modulus operator (%).</p>
146:         * <h4>Relational Operators (&lt; &lt;= == != &gt;= &gt;)</h4><p>
147:         * Relational operators compare two quantities and yield a boolean
148:         * (true or false) result. Relational operators are <em>not</em>
149:         * commutative; the interpretation of the left hand operand is
150:         * different from the right hand operand. Strings in the left hand
151:         * operand always name Conditions in if clauses or OperatingModes in
152:         * constraints. Strings in the right hand operand are always values
153:         * (or range limits). So, for example, in the play:</p><pre>
154:         * FOO == HIGH: HIGH = FOO;</pre><p>The first FOO is the name of a
155:         * Condition, the second FOO is a value to be stored in the
156:         * OperatingMode named HIGH when the Condition named FOO has a value
157:         * equal to HIGH. For clarity, it is a good practice to quote strings
158:         * used as values and not quote strings that denote Conditions and
159:         * Operating Modes.
160:         </p><p>Comparison of strings uses the default
161:         * collation sequence for characters.</p><h4>
162:         * Range Operators (in and not in)</h4><p>
163:         * Range operators test for inclusion in (or exclusion from) a range
164:         * list. The meaning is straightforward:</p><pre>
165:         * x in {1 thru 7, 10}</pre><p>is true iff
166:         * x has a value between 1 and 7 inclusive or has the value 10. A
167:         * range list is just a shorthand for a combination of less than and
168:         * greater than terms, but is easier to write and process.</p>
169:         * <h4>Boolean Constants</h4><p>The boolean constants true and false
170:         * may be used in an if clause. This is useful when developing a
171:         * playbook before the details are worked out or to deactivate certain
172:         * plays.</p>
173:         * <h3>Constraints</h3><p>
174:         * Constraints specify an allowed list of ranges to which an
175:         * <code>OperatingMode</code> can be set. The constraints from all the
176:         * plays (including those manufactured from policies) are combined
177:         * (intersected) to form the final constraint. Often this final
178:         * constraint is a single value, but when it has multiple values, the
179:         * minimum of the first range in the list is used. The constraint can
180:         * be viewed either as an expression that must be true or as an
181:         * assignment of a range list to the <code>OperatingMode</code>. For
182:         * example:</p><pre>
183:         * Opmode1 = 3
184:         * Opmode1 in {3 thru 3}
185:         * Opmode1 == 3</pre><p>
186:         * are all equivalent. The first assigns the single valued range {3
187:         * thru 3} to Opmode1. The second requires that Opmode1 have the value
188:         * 3 so that is in the range 3 thru 3. The third requires that Opmode1
189:         * be exactly equal to 3.</p><p>All forms of constraints are rewritten
190:         * as an assignment of a range list to the <code>OperatingMode</code>.
191:         * For example:</p><pre>
192:         * Opmode < 3</pre><p>
193:         * is rewritten as:</p><pre>
194:         * Opmode = {&lt;negative infinity&gt; to 3}</pre><p>
195:         * The process of intersecting the constraints from several plays may
196:         * not be clear. For example, if the if clauses of two places yielded
197:         * these two constraints:</p><pre>
198:         * opmode in {56, 128, 256, 1024}
199:         * opmode >= 128</pre><p>The combined constraint would be:</p><pre>
200:         * opmode in {128, 256, 1024}</pre><p>Another example:</p><pre>
201:         * opmode in 1 thru 10
202:         * opmode in 5 to 20</pre><p>The combined result would be:
203:         * opmode in 5 thru 10</pre><p>For a value to be included in the
204:         * combined range list, it must be included by the range lists of all
205:         * the selected plays. It is a playbook-writing error to allow plays
206:         * to be simultaneously active for which the combined range list is
207:         * empty. For example:</p><pre>
208:         * opmode in {56, 128, 256}
209:         * opmode < 56</pre><p>would be an error. Such errors are not detected
210:         * until they occur. When they do occur, they are logged and the later
211:         * constraint is ignored.</p><h3>OperatingModeConditions</h3><p>
212:         * OperatingModeConditions are intermediate variables the act as
213:         * OperatingModes in some plays and Conditions in later plays. This
214:         * allows certain plays such as those that result from policies
215:         * received from other agents to set the value of an agent-wide
216:         * OperatingMode that is then translated into component-specific
217:         * OperatingModes by using the agent-wide mode as a Condition in other
218:         * plays. For example, assume the following plays resulting from
219:         * inter-agent operating mode policies:</p><pre>
220:         * Threatcon > 3: DefensePosture = 2;
221:         * Threatcon <= 3: DefensePosture = 1;</pre><p>
222:         * and the following plays from the local playbook:</p><pre>
223:         * DefensePosture < 2: FooPlugin.keyLength = 56: AdaptivePlugin.fidelity = high;
224:         * DefensePosture >= 2: FooPlugin.keylength = 128: AdaptivePlugin.fidelity = medium;</pre><p>
225:         * The allows the outside agent to be unaware of the details of the
226:         * makeup of the agent by expressing its policy in terms of a
227:         * "DefensePosture" concept. However, the local playbook is developed with an
228:         * awareness of the agent makeup so it can contain plays to set the
229:         * operating modes of its plugins based on this
230:         * DefensePosture value.</p><h3>OperatingModePolicy</h3><p>
231:         * An OperatingModePolicy has the same syntax as a Play except that it
232:         * is prefixed with a name.</p>
233:         **/
234:        public class Parser {
235:            StreamTokenizer st;
236:            boolean pushedBack = false;
237:            ConstrainingClause cc;
238:            private LoggingService logger;
239:
240:            /**
241:             * Construct from a Reader.
242:             * @param s the Reader to read from
243:             * @param logger a LoggingService onto which error and debug
244:             * information will be written.
245:             **/
246:            public Parser(Reader s, LoggingService logger) {
247:                this .logger = logger;
248:                st = new StreamTokenizer(s);
249:                st.wordChars('_', '_');
250:                st.wordChars('[', '[');
251:                st.wordChars(']', ']');
252:                st.ordinaryChars('/', '/');
253:                st.slashStarComments(true);
254:                st.slashSlashComments(true);
255:                st.quoteChar('"');
256:                st.quoteChar('\'');
257:            }
258:
259:            /**
260:             * Parses and returns the next ConstrainingClause. The terminator
261:             * (colon) is not consumed.
262:             * @return the parsed constraining clause.
263:             * @throws IOException if an error occurs reading from the input.
264:             **/
265:            public ConstrainingClause parseConstrainingClause()
266:                    throws IOException {
267:                cc = new ConstrainingClause();
268:                parse(Operator.MAXP);
269:                ConstrainingClause result = cc;
270:                cc = null;
271:                return result;
272:            }
273:
274:            /**
275:             * Parse a series of constraints from the Reader up through a
276:             * semicolon. The terminating semicolon is consumed.
277:             * @return an array of ConstraintPhrases parsed from the input.
278:             * @throws IOException if an error occurs reading from the input.
279:             **/
280:            public ConstraintPhrase[] parseConstraints() throws IOException {
281:                List constraintPhrases = new ArrayList();
282:                while (true) {
283:                    int token = nextToken();
284:                    if (token == ';') {
285:                        break;
286:                    }
287:                    if (token != ':')
288:                        throw unexpectedTokenException("Missing semicolon");
289:                    constraintPhrases.add(parseConstraintPhrase());
290:                }
291:
292:                return (ConstraintPhrase[]) constraintPhrases
293:                        .toArray(new ConstraintPhrase[constraintPhrases.size()]);
294:            }
295:
296:            /**
297:             * Parses a single, complete Play from the input. The terminating
298:             * semicolon is consumed.
299:             * @return the parsed Play.
300:             * @throws IOException if an error occurs reading from the input.
301:             **/
302:            public Play parsePlay() throws IOException {
303:                ConstrainingClause cc = parseConstrainingClause(); // Parse the ifClause
304:                ConstraintPhrase[] cp = parseConstraints();
305:                return new Play(cc, cp);
306:            }
307:
308:            /**
309:             * Parses an entire file of Plays and returns them as an array.
310:             * @return an array of plays from the file.
311:             * @throws IOException if an error occurs reading from the input.
312:             **/
313:            public Play[] parsePlays() throws IOException {
314:                List plays = new ArrayList();
315:                readPlays: while (true) {
316:                    try {
317:                        plays.add(parsePlay());
318:                    } catch (IllegalArgumentException e) {
319:                        if (logger.isDebugEnabled()) {
320:                            logger.debug("Parse exception", e);
321:                        } else {
322:                            logger.error(e.getMessage());
323:                        }
324:                        while (st.ttype != ';') {
325:                            if (st.ttype == StreamTokenizer.TT_EOF)
326:                                break readPlays;
327:                        }
328:                    }
329:                    if (nextToken() == StreamTokenizer.TT_EOF)
330:                        break;
331:                    pushBack();
332:                }
333:                return (Play[]) plays.toArray(new Play[plays.size()]);
334:            }
335:
336:            /**
337:             * Parses an OperatingModePolicy. Syntactically, an
338:             * OperatingModePolicy is identical with a play except it is
339:             * prefixed with a name token. The name token must be a string
340:             * (quoted as necessary).
341:             * @return an OperatingModePolicy
342:             * @throws IOException if an error occurs reading from the input.
343:             **/
344:            public OperatingModePolicy parseOperatingModePolicy()
345:                    throws IOException {
346:                // pull the first token, assume it is the policy name
347:                String policyName = null;
348:                if (isWord(nextToken())) {
349:                    policyName = st.sval;
350:                } else {
351:                    pushBack();
352:                }
353:                ConstrainingClause cc = parseConstrainingClause(); // Parse the ifClause
354:                ConstraintPhrase[] cp = parseConstraints();
355:                return new OperatingModePolicy(policyName, cc, cp);
356:            }
357:
358:            /**
359:             * Parses an entire file of OperatingModePolicies and returns them
360:             * as an array.
361:             * @return an array of OperatingModePolicies from the file.
362:             * @throws IOException if an error occurs reading from the input.
363:             **/
364:            public OperatingModePolicy[] parseOperatingModePolicies()
365:                    throws IOException {
366:                List policies = new ArrayList();
367:                while (true) {
368:                    if (nextToken() == StreamTokenizer.TT_EOF)
369:                        break;
370:                    pushBack();
371:                    policies.add(parseOperatingModePolicy());
372:                }
373:                return (OperatingModePolicy[]) policies
374:                        .toArray(new OperatingModePolicy[policies.size()]);
375:            }
376:
377:            /**
378:             * Parse an if clause and push it onto the ConstrainingClause.
379:             * @param lp left left precedence of operator calling this method.
380:             */
381:            private void parse(int lp) throws IOException {
382:                if (logger.isDebugEnabled()) {
383:                    String caller = new Throwable().getStackTrace()[1]
384:                            .toString();
385:                    logger.debug("Parse from " + caller + " " + lp);
386:                }
387:                try {
388:                    int token = nextToken();
389:                    switch (token) {
390:                    default:
391:                        throw unexpectedTokenException("Unexpected token");
392:                    case '!':
393:                        parse(BooleanOperator.NOT.getLP());
394:                        cc.push(BooleanOperator.NOT);
395:                        break;
396:                    case '-':
397:                        parse(ArithmeticOperator.NEGATE.getLP());
398:                        cc.push(ArithmeticOperator.NEGATE);
399:                        break;
400:                    case '(':
401:                        parse(Operator.MAXP);
402:                        token = nextToken();
403:                        if (token != ')')
404:                            throw unexpectedTokenException("Missing close paren");
405:                        break;
406:                    case '"':
407:                    case '\'':
408:                    case StreamTokenizer.TT_WORD:
409:                        if (st.sval.equalsIgnoreCase(BooleanOperator.TRUE
410:                                .toString())) {
411:                            cc.push(BooleanOperator.TRUE);
412:                            break;
413:                        }
414:                        if (st.sval.equalsIgnoreCase(BooleanOperator.FALSE
415:                                .toString())) {
416:                            cc.push(BooleanOperator.FALSE);
417:                            break;
418:                        }
419:                        cc.push(st.sval);
420:                        break;
421:                    case StreamTokenizer.TT_NUMBER:
422:                        cc.push(new Double(st.nval));
423:                        break;
424:                    }
425:                    while (true) {
426:                        token = nextToken(); // Operator
427:                        if (token == ':') {
428:                            pushBack();
429:                            return;
430:                        }
431:                        Operator op;
432:                        switch (token) {
433:                        default:
434:                            pushBack();
435:                            return;
436:                        case '"':
437:                        case '\'':
438:                        case StreamTokenizer.TT_WORD:
439:                            if (!st.sval.equalsIgnoreCase("in")
440:                                    && !st.sval.equalsIgnoreCase("not")) {
441:                                pushBack();
442:                                return;
443:                            }
444:                            // Fall thru into parseConstraintOpValue
445:                        case '<':
446:                        case '>':
447:                        case '=':
448:                        case '!':
449:                            if (ConstraintOperator.IN.getRP() >= lp) {
450:                                // Not yet
451:                                pushBack();
452:                                return;
453:                            }
454:                            pushBack();
455:                            cc.push(parseConstraintOpValue(null));
456:                            return;
457:                        case '&':
458:                            op = BooleanOperator.AND;
459:                            break;
460:                        case '|':
461:                            op = BooleanOperator.OR;
462:                            return;
463:                        case '+':
464:                            op = ArithmeticOperator.ADD;
465:                            break;
466:                        case '-':
467:                            op = ArithmeticOperator.SUBTRACT;
468:                            break;
469:                        case '*':
470:                            op = ArithmeticOperator.MULTIPLY;
471:                            break;
472:                        case '/':
473:                            op = ArithmeticOperator.DIVIDE;
474:                            break;
475:                        }
476:                        int opp = op.getRP();
477:                        if (opp < lp) {
478:                            parse(opp);
479:                            cc.push(op);
480:                            continue;
481:                        } else {
482:                            pushBack();
483:                            return;
484:                        }
485:                    }
486:                } finally {
487:                    if (logger.isDebugEnabled())
488:                        logger.debug("Exit parse " + lp);
489:                }
490:            }
491:
492:            private ConstraintPhrase parseConstraintPhrase() throws IOException {
493:                if (!isWord(nextToken()))
494:                    throw unexpectedTokenException("Expected OperatingMode name");
495:                ConstraintPhrase cp = new ConstraintPhrase(st.sval);
496:                parseConstraintOpValue(cp);
497:                return cp;
498:            }
499:
500:            private ConstraintOpValue parseConstraintOpValue(
501:                    ConstraintOpValue cov) throws IOException {
502:                int token1 = nextToken();
503:                if (cov == null)
504:                    cov = new ConstraintOpValue();
505:
506:                switch (token1) {
507:                case '<':
508:                case '>':
509:                case '=':
510:                case '!':
511:                    int token2 = nextToken();
512:                    if (token2 == '=') {
513:                        switch (token1) {
514:                        case '<':
515:                            cov.setOperator(ConstraintOperator.LESSTHANOREQUAL);
516:                            break;
517:                        case '>':
518:                            cov
519:                                    .setOperator(ConstraintOperator.GREATERTHANOREQUAL);
520:                            break;
521:                        case '=':
522:                            cov.setOperator(ConstraintOperator.EQUAL);
523:                            break;
524:                        case '!':
525:                            cov.setOperator(ConstraintOperator.NOTEQUAL);
526:                            break;
527:                        }
528:                        token1 = nextToken();
529:                    } else {
530:                        switch (token1) {
531:                        case '=':
532:                            cov.setOperator(ConstraintOperator.ASSIGN);
533:                            break;
534:                        case '<':
535:                            cov.setOperator(ConstraintOperator.LESSTHAN);
536:                            break;
537:                        case '>':
538:                            cov.setOperator(ConstraintOperator.GREATERTHAN);
539:                            break;
540:                        default:
541:                            throw unexpectedTokenException("Malformed ConstraintOperator");
542:                        }
543:                        token1 = token2;
544:                    }
545:                    break; // end of punctuation chars case
546:                case '"':
547:                case '\'':
548:                case StreamTokenizer.TT_WORD:
549:                    if (st.sval.equalsIgnoreCase(ConstraintOperator.IN
550:                            .toString())) {
551:                        cov.setOperator(ConstraintOperator.IN);
552:                        token1 = nextToken();
553:                        break;
554:                    }
555:                    if (st.sval.equalsIgnoreCase("NOT")) {
556:                        if (isWord(nextToken())
557:                                && st.sval.equalsIgnoreCase("IN")) {
558:                            cov.setOperator(ConstraintOperator.NOTIN);
559:                            token1 = nextToken();
560:                            break;
561:                        }
562:                    }
563:                default:
564:                    throw unexpectedTokenException("Missing ConstraintOperator");
565:                }
566:                if (isWord(token1)) {
567:                    cov.setAllowedValues(new OMCRangeList(parseRange(st.sval)));
568:                } else if (token1 == StreamTokenizer.TT_NUMBER) {
569:                    cov.setAllowedValues(new OMCRangeList(
570:                            parseRange(new Double(st.nval))));
571:                } else if (token1 == '{') {
572:                    cov.setAllowedValues(parseSet());
573:                } else {
574:                    throw unexpectedTokenException("Expected range list");
575:                }
576:                return cov;
577:            }
578:
579:            private OMCRange parseRange(Comparable first) throws IOException {
580:                Class elementClass = first.getClass();
581:                int token = nextToken();
582:                if (isWord(token)) {
583:                    boolean isTo = st.sval.equalsIgnoreCase("to");
584:                    boolean isThru = st.sval.equalsIgnoreCase("thru");
585:                    if (isTo || isThru) {
586:                        Comparable last;
587:                        token = nextToken();
588:                        if (isWord(token)) {
589:                            if (elementClass == Double.class) {
590:                                throw unexpectedTokenException("Number expected");
591:                            }
592:                            last = st.sval;
593:                        } else if (token == StreamTokenizer.TT_NUMBER) {
594:                            if (elementClass == String.class) {
595:                                throw unexpectedTokenException("String expected");
596:                            }
597:                            last = new Double(st.nval);
598:                        } else {
599:                            throw unexpectedTokenException("Expected "
600:                                    + (elementClass == Double.class ? "number"
601:                                            : "string"));
602:                        }
603:                        if (isTo) {
604:                            return new OMCToRange(first, last);
605:                        } else {
606:                            return new OMCThruRange(first, last);
607:                        }
608:                    }
609:                }
610:                pushBack();
611:                return new OMCPoint(first);
612:            }
613:
614:            private OMCRangeList parseSet() throws IOException {
615:                Class elementClass = null;
616:                List values = new ArrayList();
617:
618:                while (true) {
619:                    int token1 = nextToken();
620:                    if (isWord(token1)) {
621:                        if (elementClass == Double.class) {
622:                            throw unexpectedTokenException("Number expected");
623:                        } else if (elementClass == null) {
624:                            elementClass = String.class;
625:                        }
626:                        values.add(parseRange(st.sval));
627:                    } else if (token1 == StreamTokenizer.TT_NUMBER) {
628:                        if (elementClass == String.class) {
629:                            throw unexpectedTokenException("String expected");
630:                        } else if (elementClass == null) {
631:                            elementClass = Double.class;
632:                        }
633:                        values.add(parseRange(new Double(st.nval)));
634:                    } else if (token1 == ',') {
635:                        // ignore comma
636:                    } else if (token1 == '}') {
637:                        break;
638:                    } else {
639:                        throw unexpectedTokenException("Missing close brace");
640:                    }
641:                }
642:                return new OMCRangeList((OMCRange[]) values
643:                        .toArray(new OMCRange[values.size()]));
644:            }
645:
646:            private void pushBack() {
647:                pushedBack = true;
648:            }
649:
650:            private boolean isWord(int token) {
651:                return token == StreamTokenizer.TT_WORD || token == '"'
652:                        || token == '\'';
653:            }
654:
655:            private int nextToken() throws IOException {
656:                int token;
657:                String caller = null;
658:                if (logger.isDebugEnabled())
659:                    caller = new Throwable().getStackTrace()[1].toString();
660:                if (pushedBack) {
661:                    pushedBack = false;
662:                    token = st.ttype;
663:                    if (logger.isDebugEnabled())
664:                        logger.debug("nextToken from " + caller + ": repeat "
665:                                + tokenAsString());
666:                } else {
667:                    token = st.nextToken();
668:                    if (logger.isDebugEnabled())
669:                        logger.debug("nextToken from " + caller + ": token "
670:                                + tokenAsString());
671:                }
672:                return token;
673:            }
674:
675:            private String tokenAsString() {
676:                switch (st.ttype) {
677:                case '"':
678:                case '\'':
679:                case StreamTokenizer.TT_WORD:
680:                    return st.sval;
681:                case StreamTokenizer.TT_NUMBER:
682:                    return String.valueOf(st.nval);
683:                case StreamTokenizer.TT_EOF:
684:                    return "<eof>";
685:                default:
686:                    return String.valueOf((char) st.ttype);
687:                }
688:            }
689:
690:            private IllegalArgumentException unexpectedTokenException(String mm) {
691:                String line = "line " + st.lineno();
692:                String mesg = tokenAsString();
693:                IllegalArgumentException result = new IllegalArgumentException(
694:                        mm + " on " + line + " found " + mesg);
695:                StackTraceElement[] trace = result.getStackTrace();
696:                StackTraceElement[] callerTrace = new StackTraceElement[trace.length - 1];
697:                System.arraycopy(trace, 1, callerTrace, 0, callerTrace.length);
698:                result.setStackTrace(callerTrace);
699:                return result;
700:            }
701:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.