Source Code Cross Referenced for Parser.java in  » Science » jcm1-source » edu » hws » jcm » data » 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 » jcm1 source » edu.hws.jcm.data 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*************************************************************************
002:         *                                                                        *
003:         *   1) This source code file, in unmodified form, and compiled classes   *
004:         *      derived from it can be used and distributed without restriction,  *
005:         *      including for commercial use.  (Attribution is not required       *
006:         *      but is appreciated.)                                              *
007:         *                                                                        *
008:         *    2) Modified versions of this file can be made and distributed       *
009:         *       provided:  the modified versions are put into a Java package     *
010:         *       different from the original package, edu.hws;  modified          *
011:         *       versions are distributed under the same terms as the original;   *
012:         *       and the modifications are documented in comments.  (Modification *
013:         *       here does not include simply making subclasses that belong to    *
014:         *       a package other than edu.hws, which can be done without any      *
015:         *       restriction.)                                                    *
016:         *                                                                        *
017:         *   David J. Eck                                                         *
018:         *   Department of Mathematics and Computer Science                       *
019:         *   Hobart and William Smith Colleges                                    *
020:         *   Geneva, New York 14456,   USA                                        *
021:         *   Email: eck@hws.edu          WWW: http://math.hws.edu/eck/            *
022:         *                                                                        *
023:         *************************************************************************/package edu.hws.jcm.data;
024:
025:        /**
026:         * A Parser can take a string and compile it into an ExpressionProgram.
027:         * MathObjects, such as variables and functions, can be registered with
028:         * the Parser.  This means that the Parser will recognize them in the
029:         * strings that it parses.  There are a few options that can be set to
030:         * control certain aspects of the parsing.  If a string does not have
031:         * the correct syntax for an expression, then the Parser will throw a
032:         * ParseError when it tries to parse that string.  A Parser can have a
033:         * parent.  It inherits any MathObjects registered with its parent, but
034:         * a MathObject registered with a Parser will hide any MathObject of
035:         * the same name that is registered with its parent.
036:         *    Every parser recognizes the constants pi and e and the operators
037:         * +, -, *, /, ^, and **.  The ** operator is a synonym for ^, the 
038:         * exponentiation operator.  Both unary and binary + and - are recognized.
039:         * The exponentiation operator is right associative.  The others are
040:         * left associative.
041:         */
042:        public class Parser implements  java.io.Serializable {
043:
044:            /**
045:             * An option that can be set for this parser.
046:             * If enabled, identifiers are case-sensitive.
047:             * For example, Sin, sin, and SIN will be 
048:             * treated as separate identifiers.  It really
049:             * only makes sense to enable this at the time the
050:             * Parser is first constructed.   
051:             */
052:            public static final int CASE_SENSITIVE = 1;
053:
054:            /**
055:             * An that can be set for this parser.
056:             * If enabled, mutltiplication can be indicated
057:             * implicitely, as well as with a "*".  For
058:             * example, 2x will mean 2*x.   
059:             */
060:            public static final int OPTIONAL_STARS = 2;
061:
062:            /**
063:             * An option that can be set for this parser.
064:             * If enabled, spaces are not required to separate
065:             * identifiers.  This only has an effect if one of
066:             * OPTIONAL_STARS or OPTIONAL_PARENS is also enabled.
067:             * For example, xsin(x) will be read as x*sin(x),
068:             * and sine will be read as sin(e).
069:             */
070:            public static final int OPTIONAL_SPACES = 4;
071:
072:            /**
073:             * An option that can be set for this parser.
074:             * If enabled, brackets, [ and ], can be used for grouping.
075:             */
076:            public static final int BRACKETS = 8;
077:
078:            /**
079:             * An option that can be set for this parser.
080:             * If enabled, braces, { and }, can be used for grouping.
081:             */
082:            public static final int BRACES = 16;
083:
084:            /**
085:             * An option that can be set for this parser.
086:             * If enabled, the "?" operator can be used in expressions, along with the
087:             * logical operators &, |, ~, =, <, >, <>, <=, >=.
088:             * The words "and", "or", and "not" can be used
089:             * in place of &, |, and ~.  These words are
090:             * treated in a case-insensitive way, even if
091:             * the CASE_SENSITIVE option is on.  When this
092:             * option is set, it is legal to call the
093:             * parseLogical method to parse a boolean-valued
094:             * expression.  This option is enabled by default.
095:             */
096:            public static final int BOOLEANS = 32;
097:
098:            /**
099:             * An option that can be set for this parser.
100:             * If enabled, the factorial operator, !, is recognized.           
101:             */
102:            public static final int FACTORIAL = 64;
103:
104:            /**
105:             * An option that can be set for this parser.
106:             * The character "_", which can usually
107:             * be used just like a letter, is
108:             * not allowed in identifers.           
109:             */
110:            public static final int NO_UNDERSCORE_IN_IDENTIFIERS = 128;
111:
112:            /**
113:             * An option that can be set for this parser.
114:             * Digits 0 through 9, which can usually be
115:             * used in an identifier after the first
116:             * character, are not allowed in identifiers.           
117:             */
118:            public static final int NO_DIGITS_IN_IDENTIFIERS = 256;
119:
120:            /**
121:             * An option that can be set for this parser.
122:             * If enabled, parentheses are optional around
123:             * the parameter of a standard function.  If the
124:             * parentheses are omited, then the argument is
125:             * the term that follows the function name.
126:             * For example, "sin x + 1" means "sin(x) + 1"
127:             * while "sin x * cos x" means "sin( x*cos(x) )".           
128:             */
129:            public static final int OPTIONAL_PARENS = 512;
130:
131:            /**
132:             * An option that can be set for this parser.
133:             * When enabled, the standard functions are
134:             * registered with the parser.  This option
135:             * is enabled by default.  The standard
136:             * functions are: sin, cos, tan, cot, sec,
137:             * csc, arcsin, arccos, arctan, exp, ln,
138:             * log2, log10, sqrt, cubert, abs, round,
139:             * floor, ceiling, trunc.           
140:             */
141:            public static final int STANDARD_FUNCTIONS = 1024;
142:
143:            /**     
144:             * The default options set that is used for
145:             * a newly created Parser, if none is specified 
146:             * in the Constructor.  It includes the options BOOLEANS and STANDARD_FUNCTIONS.
147:             */
148:            public static final int DEFAULT_OPTIONS = BOOLEANS
149:                    | STANDARD_FUNCTIONS;
150:
151:            /**  
152:             * The set of options that have been enabled for this parser.
153:             */
154:            protected int options;
155:
156:            /**                    
157:             * The symbol table that contains the MathObjects
158:             * that have been registered with this parser.   
159:             */
160:            protected SymbolTable symbols;
161:
162:            /**
163:             * Construct a Parser with no parent and with the default options,
164:             * BOOLEANS and STANDARD_FUNCTIONS.
165:             */
166:            public Parser() {
167:                this (null, DEFAULT_OPTIONS);
168:            }
169:
170:            /**
171:             * Create a Parser with the specified parent.  The options for this
172:             * parser are inherited from the parent, if parent is non-null.
173:             * If parent is null, the option set is empty.
174:             */
175:            public Parser(Parser parent) {
176:                this (parent, 0);
177:            }
178:
179:            /**
180:             * Create a Parser with the spedified option set and with no parent.
181:             */
182:            public Parser(int options) {
183:                this (null, options);
184:            }
185:
186:            /**
187:             * Create a Parser with the specified parent. The options for this
188:             * parser consist of the option set from the parent, together with
189:             * any additional options in the specified options set.
190:             *
191:             * @param parent parent of this Parser, possibly null.
192:             * @param options additional options, in addition to ones inherited from parent.
193:             */
194:            public Parser(Parser parent, int options) {
195:                if (parent == null) {
196:                    symbols = new SymbolTable();
197:                    symbols.add(new Constant("e", Math.E));
198:                    symbols.add(new Constant("pi", Math.PI));
199:                } else {
200:                    symbols = new SymbolTable(parent.symbols);
201:                    this .options = parent.options;
202:                }
203:                addOptions(options);
204:            }
205:
206:            /**
207:             * Add the options in the option set newOptions to this Parser's option set.
208:             * The value of newOptions can be one of the option constants defined in this
209:             * class, such as OPTIONAL_STARS, or it can consist of several option constants
210:             * OR-ed together.
211:             *
212:             */
213:            public void addOptions(int newOptions) {
214:                if (((newOptions & STANDARD_FUNCTIONS) != 0)
215:                        && ((options & STANDARD_FUNCTIONS) == 0)) {
216:                    for (int opCode = ExpressionProgram.CUBERT; opCode <= ExpressionProgram.SIN; opCode++)
217:                        symbols.add(new StandardFunction(opCode));
218:                }
219:                options = options | newOptions;
220:            }
221:
222:            /**
223:             * Parse the string str and create the corresponding expression.
224:             * The expression must be numeric-valued, not logical.  There can't
225:             * be any extra characters in str after the expression. If a syntax
226:             * error is found, a ParseError will be thrown.
227:             *
228:             * @param str String to parse.
229:             * @return the expression defined by the string.
230:             */
231:            public ExpressionProgram parse(String str) {
232:                ParserContext context = new ParserContext(str, options, symbols);
233:                // The ParserContext holds all the information relevant to the
234:                // parsing of str, including str itself and the ExpressionProgram
235:                // that is being generated.  See the ParserContext class for more info.
236:                if (str == null)
237:                    throw new ParseError("Can't parse a null string.", context);
238:                if (context.look() == ParserContext.END_OF_STRING)
239:                    throw new ParseError("Can't parse an empty string.",
240:                            context);
241:                boolean isBool;
242:                if ((options & BOOLEANS) != 0)
243:                    isBool = parseLogicalExpression(context);
244:                else
245:                    isBool = parseExpression(context);
246:                if (context.look() != ParserContext.END_OF_STRING)
247:                    throw new ParseError(
248:                            "Extra data found after the end of a complete legal expression.",
249:                            context);
250:                if (isBool)
251:                    throw new ParseError(
252:                            "Found a logical-valued expression instead of a numeric expression.",
253:                            context);
254:                context.prog.trim();
255:                context.prog.sourceString = str;
256:                return context.prog;
257:            }
258:
259:            /**
260:             * Parse the String, str, and create a corresponding logical-valued expression.
261:             * The expression must be logical-valued, such as "x > 0", not numeric.  There can't
262:             * be any extra characters in str after the expression. If a syntax
263:             * error is found, a ParseError will be thrown.  It is not legal to call this
264:             * method if the BOOLEANS option is not set.
265:             *
266:             * @param str String to parse.
267:             * @return the logical-valued expression defined by str.
268:             */
269:            public ExpressionProgram parseLogical(String str) {
270:                if ((options & BOOLEANS) == 0)
271:                    throw new IllegalArgumentException(
272:                            "Internal Error:  Attempt to parse a logical-valued expression, but BOOLEANS option is not turned on.");
273:                ParserContext context = new ParserContext(str, options, symbols);
274:                if (str == null)
275:                    throw new ParseError("Can't parse a null string.", context);
276:                if (context.look() == ParserContext.END_OF_STRING)
277:                    throw new ParseError("Can't parse an empty string.",
278:                            context);
279:                boolean isBool = parseLogicalExpression(context);
280:                if (context.look() != ParserContext.END_OF_STRING)
281:                    throw new ParseError(
282:                            "Extra data found after the end of a complete legal expression.",
283:                            context);
284:                if (!isBool)
285:                    throw new ParseError(
286:                            "Found a numeric-valued expression instead of a logical expression.",
287:                            context);
288:                context.prog.trim();
289:                return context.prog;
290:            }
291:
292:            //---------- Wrapper functions for accessing the symbol table --------------
293:
294:            /**
295:             * Get the MathObject that has been registered with the parser
296:             * under the given name.  If the CASE_SENSITIVE option is not set,
297:             * names are converted to lower case for the purpose of 
298:             * registering and retrieving registered objects.
299:             */
300:            public MathObject get(String name) {
301:                if ((options & Parser.CASE_SENSITIVE) != 0)
302:                    return symbols.get(name);
303:                else
304:                    return symbols.get(name.toLowerCase());
305:            }
306:
307:            /**
308:             * Register the MathObject with the Parser, associating it with its
309:             * name.  An error will occur if the name is null.  If the CASE_SENSITIVE
310:             * option is not set, names are converted to lower case for the purpose of 
311:             * registering and retrieving registered objects.
312:             */
313:            public void add(MathObject sym) {
314:                if ((options & Parser.CASE_SENSITIVE) != 0)
315:                    symbols.add(sym);
316:                else
317:                    symbols.add(sym.getName().toLowerCase(), sym);
318:            }
319:
320:            /**
321:             * Deregister the MathObject with the given name, if there is one
322:             * registered with the Parser.  If the name is not registered, nothing
323:             * happens and no error occurs.
324:             *
325:             * @param name MathObject to deregister.
326:             */
327:            public void remove(String name) {
328:                if (name == null)
329:                    return;
330:                else if ((options & Parser.CASE_SENSITIVE) != 0)
331:                    symbols.remove(name);
332:                else
333:                    symbols.remove(name.toLowerCase());
334:            }
335:
336:            // ------------------------- The  parsing code -------------------------
337:
338:            // The remaining routines in this class implement a recursive descent parser
339:            // for expressions.  These routines would be private, except that it might
340:            // be necessary for a ParserExtension to call them.  The ParserContext parameter
341:            // holds information such as the string that is being parsed and the ExpressionProgram
342:            // that is being generated.  See the ParseContext class for more information.
343:
344:            /**
345:             *  Called as part of the parsing process.  From outside this class, this would
346:             *  probably be called only by a ParserExtension.
347:             */
348:            public boolean parseLogicalExpression(ParserContext context) {
349:                boolean isBool = parseLogicalTerm(context);
350:                int tok = context.look();
351:                if (tok == ParserContext.OPCHARS
352:                        && context.tokenString.equals("&") && !isBool)
353:                    throw new ParseError(
354:                            "The AND operator can only be used with logical expressions.",
355:                            context);
356:                while (tok == ParserContext.OPCHARS
357:                        && context.tokenString.equals("&")) {
358:                    context.next();
359:                    if (!parseLogicalTerm(context))
360:                        throw new ParseError(
361:                                "The AND operator can only be used with logical expressions.",
362:                                context);
363:                    context.prog.addCommand(ExpressionProgram.AND);
364:                    tok = context.look();
365:                }
366:                if (tok == ParserContext.OPCHARS
367:                        && context.tokenString.equals("?")) {
368:                    if (!isBool)
369:                        throw new ParseError(
370:                                "The conditional operator, ?, can only be applied to a logical-valued expression.",
371:                                context);
372:                    ExpressionProgram trueCase, falseCase;
373:                    ExpressionProgram saveProg = context.prog;
374:                    context.next();
375:                    trueCase = new ExpressionProgram();
376:                    context.prog = trueCase;
377:                    if (parseLogicalExpression(context))
378:                        throw new ParseError(
379:                                "The cases in a conditional expression cannot be logical-valued expressions.",
380:                                context);
381:                    tok = context.look();
382:                    if (tok == ParserContext.OPCHARS
383:                            && context.tokenString.equals(":")) {
384:                        context.next();
385:                        falseCase = new ExpressionProgram();
386:                        context.prog = falseCase;
387:                        if (parseLogicalExpression(context))
388:                            throw new ParseError(
389:                                    "The cases in a conditional expression cannot be logical-valued expressions.",
390:                                    context);
391:                    } else
392:                        falseCase = null;
393:                    context.prog = saveProg;
394:                    context.prog.addCommandObject(new ConditionalExpression(
395:                            trueCase, falseCase));
396:                    return false;
397:                } else
398:                    return isBool;
399:            }
400:
401:            /**
402:             *  Called as part of the parsing process.  From outside this class, this would
403:             *  probably be called only by a ParserExtension.
404:             */
405:            public boolean parseLogicalTerm(ParserContext context) {
406:                boolean isBool = parseLogicalFactor(context);
407:                int tok = context.look();
408:                if (tok == ParserContext.OPCHARS
409:                        && context.tokenString.equals("|") && !isBool)
410:                    throw new ParseError(
411:                            "The OR operator can only be used with logical expressions.",
412:                            context);
413:                while (tok == ParserContext.OPCHARS
414:                        && context.tokenString.equals("|")) {
415:                    context.next();
416:                    if (!parseLogicalFactor(context))
417:                        throw new ParseError(
418:                                "The OR operator can only be used with logical expressions.",
419:                                context);
420:                    context.prog.addCommand(ExpressionProgram.OR);
421:                    tok = context.look();
422:                }
423:                return isBool;
424:            }
425:
426:            /**
427:             *  Called as part of the parsing process.  From outside this class, this would
428:             *  probably be called only by a ParserExtension.
429:             */
430:            public boolean parseLogicalFactor(ParserContext context) {
431:                int tok = context.look();
432:                int notCt = 0;
433:                while (tok == ParserContext.OPCHARS
434:                        && context.tokenString.equals("~")) {
435:                    context.next();
436:                    tok = context.look();
437:                    notCt++;
438:                }
439:                boolean isBool = parseRelation(context);
440:                if (notCt > 0 && !isBool)
441:                    throw new ParseError(
442:                            "The NOT operator can only be used with logical expressions.",
443:                            context);
444:                if (notCt % 2 == 1)
445:                    context.prog.addCommand(ExpressionProgram.NOT);
446:                return isBool;
447:            }
448:
449:            /**
450:             *  Called as part of the parsing process.  From outside this class, this would
451:             *  probably be called only by a ParserExtension.
452:             */
453:            public boolean parseRelation(ParserContext context) {
454:                boolean isBool = parseExpression(context);
455:                int tok = context.look();
456:                if (tok != ParserContext.OPCHARS)
457:                    return isBool;
458:                int rel = 0;
459:                if (context.tokenString.equals("="))
460:                    rel = ExpressionProgram.EQ;
461:                else if (context.tokenString.equals("<"))
462:                    rel = ExpressionProgram.LT;
463:                else if (context.tokenString.equals(">"))
464:                    rel = ExpressionProgram.GT;
465:                else if (context.tokenString.equals("<="))
466:                    rel = ExpressionProgram.LE;
467:                else if (context.tokenString.equals(">="))
468:                    rel = ExpressionProgram.GE;
469:                else if (context.tokenString.equals("<>"))
470:                    rel = ExpressionProgram.NE;
471:                if (rel == 0)
472:                    return isBool;
473:                if (isBool)
474:                    throw new ParseError(
475:                            "A relational operator can only be used with numerical expressions.",
476:                            context);
477:                context.next();
478:                if (parseExpression(context))
479:                    throw new ParseError(
480:                            "A relational operator can only be used with numerical expressions.",
481:                            context);
482:                tok = context.look();
483:                if (tok == ParserContext.OPCHARS
484:                        && (context.tokenString.equals("=")
485:                                || context.tokenString.equals("<")
486:                                || context.tokenString.equals(">")
487:                                || context.tokenString.equals("<=")
488:                                || context.tokenString.equals(">=") || context.tokenString
489:                                .equals("<>")))
490:                    throw new ParseError(
491:                            "It is illegal to string together relations operators; use \"AND\" instead.",
492:                            context);
493:                context.prog.addCommand(rel);
494:                return true;
495:            }
496:
497:            /**
498:             *  Called as part of the parsing process.  From outside this class, this would
499:             *  probably be called only by a ParserExtension.
500:             */
501:            public boolean parseExpression(ParserContext context) {
502:                boolean neg = false;
503:                int tok = context.look();
504:                if (tok == ParserContext.OPCHARS
505:                        && (context.tokenString.equals("+") || context.tokenString
506:                                .equals("-"))) {
507:                    neg = (context.tokenString.equals("-"));
508:                    context.next();
509:                }
510:                boolean isBool = parseTerm(context);
511:                if (neg) {
512:                    if (isBool)
513:                        throw new ParseError(
514:                                "A unary + or - cannot be applied to a logical expression.",
515:                                context);
516:                    context.prog.addCommand(ExpressionProgram.UNARY_MINUS);
517:                }
518:                tok = context.look();
519:                if (tok == ParserContext.OPCHARS
520:                        && (context.tokenString.equals("+") || context.tokenString
521:                                .equals("-")) && isBool)
522:                    throw new ParseError(
523:                            "A + or - operator cannot be applied to logical operands.",
524:                            context);
525:                while (tok == ParserContext.OPCHARS
526:                        && (context.tokenString.equals("+") || context.tokenString
527:                                .equals("-"))) {
528:                    context.next();
529:                    int opcode = (context.tokenString.equals("+") ? ExpressionProgram.PLUS
530:                            : ExpressionProgram.MINUS);
531:                    if (parseTerm(context))
532:                        throw new ParseError(
533:                                "A + or - operator cannot be applied to logical operands.",
534:                                context);
535:                    context.prog.addCommand(opcode);
536:                    tok = context.look();
537:                }
538:                return isBool;
539:            }
540:
541:            /**
542:             *  Called as part of the parsing process.  From outside this class, this would
543:             *  probably be called only by a ParserExtension.
544:             */
545:            public boolean parseTerm(ParserContext context) {
546:                boolean implicitStar = false;
547:                boolean isBool = parsePrimary(context);
548:                int tok = context.look();
549:                String ts = context.tokenString;
550:                implicitStar = !isBool
551:                        && (options & OPTIONAL_STARS) != 0
552:                        && (tok == ParserContext.NUMBER
553:                                || tok == ParserContext.IDENTIFIER || (tok == ParserContext.OPCHARS && (ts
554:                                .equals("(")
555:                                || ts.equals("[") || ts.equals("{"))));
556:                if (tok == ParserContext.OPCHARS
557:                        && (ts.equals("*") || ts.equals("/")) && isBool)
558:                    throw new ParseError(
559:                            "A * or / operator cannot be applied to logical operands.",
560:                            context);
561:                while (implicitStar || tok == ParserContext.OPCHARS
562:                        && (ts.equals("*") || ts.equals("/"))) {
563:                    if (!implicitStar)
564:                        context.next();
565:                    int opcode = (implicitStar || ts.equals("*") ? ExpressionProgram.TIMES
566:                            : ExpressionProgram.DIVIDE);
567:                    if (parsePrimary(context))
568:                        throw new ParseError(
569:                                "A * or / operator cannot be applied to logical operands.",
570:                                context);
571:                    context.prog.addCommand(opcode);
572:                    tok = context.look();
573:                    ts = context.tokenString;
574:                    implicitStar = !isBool
575:                            && (options & OPTIONAL_STARS) != 0
576:                            && (tok == ParserContext.NUMBER
577:                                    || tok == ParserContext.IDENTIFIER || (tok == ParserContext.OPCHARS && (ts
578:                                    .equals("(")
579:                                    || ts.equals("[") || ts.equals("{"))));
580:                }
581:                return isBool;
582:            }
583:
584:            /**
585:             *  Called as part of the parsing process.  From outside this class, this would
586:             *  probably be called only by a ParserExtension.
587:             */
588:            public boolean parsePrimary(ParserContext context) {
589:                boolean isBool = parseFactor(context);
590:                int tok = context.look();
591:                if (tok == ParserContext.OPCHARS
592:                        && context.tokenString.equals("^")) {
593:                    if (isBool)
594:                        throw new ParseError(
595:                                "The exponentiation operator cannot be applied to logical operands.",
596:                                context);
597:                    context.next();
598:                    if (parsePrimary(context))
599:                        throw new ParseError(
600:                                "The exponentiation operator cannot be applied to logical operands.",
601:                                context);
602:                    context.prog.addCommand(ExpressionProgram.POWER);
603:                }
604:                return isBool;
605:            }
606:
607:            /**
608:             *  Called as part of the parsing process.  From outside this class, this would
609:             *  probably be called only by a ParserExtension.
610:             */
611:            public boolean parseFactor(ParserContext context) {
612:                boolean isBool = false;
613:                int tok = context.next();
614:                if (tok == ParserContext.NUMBER)
615:                    context.prog.addConstant(context.tokenValue);
616:                else if (tok == ParserContext.IDENTIFIER)
617:                    parseWord(context);
618:                else if (tok == ParserContext.END_OF_STRING)
619:                    throw new ParseError(
620:                            "Data ended in the middle of an incomplete expression.",
621:                            context);
622:                else if (tok != ParserContext.OPCHARS)
623:                    throw new ParseError(
624:                            "Internal error:  Unknown token type.", context);
625:                else if (context.tokenString.equals("("))
626:                    isBool = parseGroup('(', ')', context);
627:                else if (context.tokenString.equals("[")
628:                        && ((options & Parser.BRACKETS) != 0))
629:                    isBool = parseGroup('[', ']', context);
630:                else if (context.tokenString.equals("{")
631:                        && ((options & Parser.BRACES) != 0))
632:                    isBool = parseGroup('{', '}', context);
633:                else if (context.tokenString.equals("}")
634:                        && ((options & Parser.BRACES) != 0))
635:                    throw new ParseError(
636:                            "Misplaced right brace with no matching left brace.",
637:                            context);
638:                else if (context.tokenString.equals("]")
639:                        && ((options & Parser.BRACKETS) != 0))
640:                    throw new ParseError(
641:                            "Misplaced right bracket with no matching left bracket.",
642:                            context);
643:                else if (context.tokenString.equals(")"))
644:                    throw new ParseError(
645:                            "Misplaced right parenthesis with no matching left parenthesis.",
646:                            context);
647:                else
648:                    throw new ParseError("Illegal or misplaced character \""
649:                            + context.tokenString.charAt(0) + "\"", context);
650:                if ((options & FACTORIAL) != 0) {
651:                    tok = context.look();
652:                    while (tok == ParserContext.OPCHARS
653:                            && context.tokenString.equals("!")) {
654:                        if (isBool)
655:                            throw new ParseError(
656:                                    "The factorial operator cannot be applied to a logical value.",
657:                                    context);
658:                        context.next();
659:                        context.prog.addCommand(ExpressionProgram.FACTORIAL);
660:                        tok = context.look();
661:                    }
662:                }
663:                return isBool;
664:            }
665:
666:            // Helper routine for parsePrimary.  If a ParserExtension needs to call this,
667:            // it should look ahead to make sure there is a (, [, or { and then call
668:            // parsePrimary.
669:            /**
670:             *  Called as part of the parsing process.  From outside this class, this would
671:             *  probably be called only by a ParserExtension.
672:             */
673:            private boolean parseGroup(char open, char close,
674:                    ParserContext context) {
675:                boolean isBool = (options & Parser.BOOLEANS) == 0 ? parseExpression(context)
676:                        : parseLogicalExpression(context);
677:                int tok = context.look();
678:                if (tok == ParserContext.OPCHARS
679:                        && context.tokenString.equals("" + close))
680:                    context.next();
681:                else
682:                    throw new ParseError("Missing \"" + close
683:                            + "\" to match a previous \"" + open + "\".",
684:                            context);
685:                return isBool;
686:            }
687:
688:            // Helper routine for parsePrimary.  If a ParserExtension needs to call this,
689:            // it should look ahead to make sure there is an identifier and then call
690:            // parsePrimary.
691:            /**
692:             *  Called as part of the parsing process.  From outside this class, this would
693:             *  probably be called only by a ParserExtension.
694:             */
695:            private void parseWord(ParserContext context) {
696:                if (context.tokenObject == null)
697:                    throw new ParseError("Unknown word \""
698:                            + context.tokenString
699:                            + "\" encountered in an expression.", context);
700:                if (context.tokenObject instanceof  Variable
701:                        || context.tokenObject instanceof  Constant)
702:                    context.prog
703:                            .addCommandObject((ExpressionCommand) context.tokenObject);
704:                else if (context.tokenObject instanceof  StandardFunction) {
705:                    StandardFunction f = (StandardFunction) context.tokenObject;
706:                    int tok = context.look();
707:                    if (tok == ParserContext.OPCHARS
708:                            && (context.tokenString.equals("(")
709:                                    || (context.tokenString.equals("[") && ((options & BRACKETS) != 0)) || (context.tokenString
710:                                    .equals("{") && ((options & BRACES) != 0)))) {
711:                        context.next();
712:                        boolean isBool;
713:                        if (context.tokenString.equals("("))
714:                            isBool = parseGroup('(', ')', context);
715:                        else if (context.tokenString.equals("["))
716:                            isBool = parseGroup('[', ']', context);
717:                        else
718:                            isBool = parseGroup('{', '}', context);
719:                        if (isBool)
720:                            throw new ParseError(
721:                                    "The argument of a function must be a numerical expression.",
722:                                    context);
723:                    } else {
724:                        if ((options & OPTIONAL_PARENS) == 0)
725:                            throw new ParseError(
726:                                    "Parentheses required around argument of standard function \""
727:                                            + f.getName() + "\".", context);
728:                        if (parseTerm(context))
729:                            throw new ParseError(
730:                                    "The argument of a function must be a numerical expression.",
731:                                    context);
732:                    }
733:                    context.prog.addCommand(f.getOpCode());
734:                } else if (context.tokenObject instanceof  ParserExtension)
735:                    ((ParserExtension) context.tokenObject).doParse(this ,
736:                            context);
737:                else if (!(context.tokenObject instanceof  ExpressionCommand))
738:                    throw new ParseError("Unexpected word \""
739:                            + context.tokenObject.getName()
740:                            + "\" encountered in an expression.", context);
741:                else
742:                    throw new ParseError("Unimplemented word \""
743:                            + context.tokenObject.getName()
744:                            + "\" encountered in an expression.", context);
745:            }
746:
747:        } // end class Parser
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.