~ubuntu-branches/ubuntu/oneiric/electric/oneiric

« back to all changes in this revision

Viewing changes to com/sun/electric/database/variable/CodeExpression.java

  • Committer: Bazaar Package Importer
  • Author(s): Onkar Shinde
  • Date: 2010-01-09 16:26:04 UTC
  • mfrom: (1.1.4 upstream) (3.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20100109162604-1ypvmy8ijmlc6oq7
Tags: 8.10-1
* New upstream version.
* debian/control
  - Add libjava3d-java and quilt build dependencies.
  - Update standards version to 3.8.3.
  - Add libjava3d-java as recommends to binary package.
* debian/rules
  - Use quilt patch system instead of simple patchsys.
  - Add java3d related jar files to DEB_JARS.
* debian/patches/*
  - Update as per current upstream source. Convert to quilt.
* debian/ant.properties
  - Do not disable 3D plugin anymore.
  - Use new property to disable compilation of OS X related classes.
* debian/wrappers/electric
  - Add java3d related jar files to runtime classpath.
* debian/README.source
  - Change text to the appropriate one for quilt.

Show diffs side-by-side

added added

removed removed

Lines of Context:
49
49
 */
50
50
public class CodeExpression implements Serializable {
51
51
    // Variable flags in C Electric
52
 
        /** variable is interpreted code (with VCODE2) */       private static final int VCODE1 =                040;
53
 
        /** variable is interpreted code (with VCODE1) */       private static final int VCODE2 =        04000000000;
54
 
        /** variable is LISP */                                                         private static final int VSPICE =             VCODE1;
55
 
        /** variable is TCL */                                                          private static final int VTCL =               VCODE2;
56
 
        /** variable is Java */                                                         private static final int VJAVA =      (VCODE1|VCODE2);
57
52
 
58
 
    private static final HashMap <String,CodeExpression> javaExpressions = new HashMap<String,CodeExpression>();
59
 
    private static final HashMap <String,CodeExpression> spiceExpressions = new HashMap<String,CodeExpression>();
60
 
    private static final HashMap <String,CodeExpression> tclExpressions = new HashMap<String,CodeExpression>();
 
53
    /** variable is interpreted code (with VCODE2) */
 
54
    private static final int VCODE1 = 040;
 
55
    /** variable is interpreted code (with VCODE1) */
 
56
    private static final int VCODE2 = 04000000000;
 
57
    /** variable is LISP */
 
58
    private static final int VSPICE = VCODE1;
 
59
    /** variable is TCL */
 
60
    private static final int VTCL = VCODE2;
 
61
    /** variable is Java */
 
62
    private static final int VJAVA = (VCODE1 | VCODE2);
 
63
    private static final HashMap<String, CodeExpression> javaExpressions = new HashMap<String, CodeExpression>();
 
64
    private static final HashMap<String, CodeExpression> spiceExpressions = new HashMap<String, CodeExpression>();
 
65
    private static final HashMap<String, CodeExpression> tclExpressions = new HashMap<String, CodeExpression>();
61
66
    private static long numValueOfs;
62
 
    /** For replacing @variable */ private static final Pattern pPat = Pattern.compile("P\\(\"(\\w+)\"\\)");
63
 
 
 
67
    /** For replacing @variable */
 
68
    private static final Pattern pPat = Pattern.compile("P\\(\"(\\w+)\"\\)");
64
69
    private final Code code;
65
70
    private final String expr;
66
71
    private final Set<Variable.Key> depends;
75
80
     * value should be evaluated. If NONE, no evaluation is done.
76
81
     */
77
82
    public static enum Code {
78
 
        /** Indicator that code is in Java. */  JAVA("Java", VJAVA),
79
 
                /** Indicator that code is in Lisp. */  SPICE("Spice", VSPICE),
80
 
                /** Indicator that code is in TCL. */   TCL("TCL (not avail.)", VTCL),
81
 
                /** Indicator that this is not code. */ NONE("Not Code", 0);
82
83
 
 
84
        /** Indicator that code is in Java. */
 
85
        JAVA("Java", VJAVA),
 
86
        /** Indicator that code is in Lisp. */
 
87
        SPICE("Spice", VSPICE),
 
88
        /** Indicator that code is in TCL. */
 
89
        TCL("TCL (not avail.)", VTCL),
 
90
        /** Indicator that this is not code. */
 
91
        NONE("Not Code", 0);
83
92
        private final String name;
84
93
        private final int cFlags;
85
94
        private static final Code[] allCodes = Code.class.getEnumConstants();
89
98
            this.cFlags = cFlags;
90
99
        }
91
100
 
92
 
                /**
93
 
                 * Method to return the bits value of this code type.
94
 
                 * This is used in I/O.
95
 
                 * @return the bits value of this code type.
96
 
                 */
97
 
        public int getCFlags() { return cFlags; }
 
101
        /**
 
102
         * Method to return the bits value of this code type.
 
103
         * This is used in I/O.
 
104
         * @return the bits value of this code type.
 
105
         */
 
106
        public int getCFlags() {
 
107
            return cFlags;
 
108
        }
98
109
 
99
 
                /**
100
 
                 * Method to return a printable version of this Code.
101
 
                 * @return a printable version of this Code.
102
 
                 */
103
 
        public String toString() { return name; }
 
110
        /**
 
111
         * Method to return a printable version of this Code.
 
112
         * @return a printable version of this Code.
 
113
         */
 
114
        public String toString() {
 
115
            return name;
 
116
        }
104
117
 
105
118
        /**
106
119
         * Method to get an iterator over all Code types.
107
120
         */
108
 
        public static Iterator<Code> getCodes() { return ArrayIterator.iterator(allCodes); }
 
121
        public static Iterator<Code> getCodes() {
 
122
            return ArrayIterator.iterator(allCodes);
 
123
        }
109
124
 
110
 
                /**
111
 
                 * Method to convert a bits value to a Code object.
112
 
                 * @param cBits the bits value (from I/O).
113
 
                 * @return the Code associated with those bits.
114
 
                 */
115
 
        public static Code getByCBits(int cBits)
116
 
        {
117
 
            switch (cBits & (VCODE1|VCODE2))
118
 
            {
119
 
                case VJAVA: return JAVA;
120
 
                case VSPICE: return SPICE;
121
 
                case VTCL: return TCL;
122
 
                default: return NONE;
 
125
        /**
 
126
         * Method to convert a bits value to a Code object.
 
127
         * @param cBits the bits value (from I/O).
 
128
         * @return the Code associated with those bits.
 
129
         */
 
130
        public static Code getByCBits(int cBits) {
 
131
            switch (cBits & (VCODE1 | VCODE2)) {
 
132
                case VJAVA:
 
133
                    return JAVA;
 
134
                case VSPICE:
 
135
                    return SPICE;
 
136
                case VTCL:
 
137
                    return TCL;
 
138
                default:
 
139
                    return NONE;
123
140
            }
124
141
        }
125
142
 
126
 
                /**
127
 
                 * Method to get a Code constant by its ordinal number.
128
 
                 * @param ordinal the ordinal number of this Code constant ( as returned by ordinal()
129
 
                 * @return the Code associated with this ordinal number.
130
 
                 */
131
 
        public static Code getByOrdinal(int ordinal)
132
 
        {
 
143
        /**
 
144
         * Method to get a Code constant by its ordinal number.
 
145
         * @param ordinal the ordinal number of this Code constant ( as returned by ordinal()
 
146
         * @return the Code associated with this ordinal number.
 
147
         */
 
148
        public static Code getByOrdinal(int ordinal) {
133
149
            return allCodes[ordinal];
134
150
        }
135
151
    }
151
167
        EvalSpice.ParseException parseException = null;
152
168
        try {
153
169
            switch (code) {
154
 
                case JAVA: exprTree = parse(patchedExpr, true); break;
155
 
                case SPICE: exprTree = parse(patchedExpr, false); break;
156
 
                default: throw new EvalSpice.ParseException("Unsupported code " + code);
 
170
                case JAVA:
 
171
                    exprTree = parse(patchedExpr, true);
 
172
                    break;
 
173
                case SPICE:
 
174
                    exprTree = parse(patchedExpr, false);
 
175
                    break;
 
176
                default:
 
177
                    throw new EvalSpice.ParseException("Unsupported code " + code);
157
178
            }
158
179
 
159
180
        } catch (EvalSpice.ParseException e) {
174
195
            exprTree.appendText(sb, Expr.MIN_PRECEDENCE);
175
196
            spiceTextPar = new String(sb);
176
197
        }
177
 
     }
 
198
    }
178
199
 
179
 
    private Object writeReplace() { return new CodeExpressionKey(this); }
 
200
    private Object writeReplace() {
 
201
        return new CodeExpressionKey(this);
 
202
    }
180
203
 
181
204
    private static class CodeExpressionKey extends EObjectInputStream.Key<CodeExpression> {
182
 
        public CodeExpressionKey() {}
183
 
        private CodeExpressionKey(CodeExpression ce) { super(ce); }
 
205
 
 
206
        public CodeExpressionKey() {
 
207
        }
 
208
 
 
209
        private CodeExpressionKey(CodeExpression ce) {
 
210
            super(ce);
 
211
        }
184
212
 
185
213
        @Override
186
214
        public void writeExternal(EObjectOutputStream out, CodeExpression ce) throws IOException {
198
226
 
199
227
    public static synchronized CodeExpression valueOf(String expression, Code code) {
200
228
        numValueOfs++;
201
 
        HashMap<String,CodeExpression> allExpressions;
 
229
        HashMap<String, CodeExpression> allExpressions;
202
230
        switch (code) {
203
 
            case JAVA: allExpressions = javaExpressions; break;
204
 
            case SPICE: allExpressions = spiceExpressions; break;
205
 
            case TCL: allExpressions = tclExpressions; break;
206
 
            default: throw new IllegalArgumentException("code");
 
231
            case JAVA:
 
232
                allExpressions = javaExpressions;
 
233
                break;
 
234
            case SPICE:
 
235
                allExpressions = spiceExpressions;
 
236
                break;
 
237
            case TCL:
 
238
                allExpressions = tclExpressions;
 
239
                break;
 
240
            default:
 
241
                throw new IllegalArgumentException("code");
207
242
        }
208
243
        CodeExpression ce = allExpressions.get(expression);
209
244
        if (ce == null) {
213
248
        return ce;
214
249
    }
215
250
 
216
 
    public Code getCode() { return code; }
217
 
    public boolean isJava() { return code == Code.JAVA; }
218
 
    public String getExpr() { return expr; }
219
 
    public Set<Variable.Key> dependsOn() { return depends; }
220
 
    public EvalSpice.ParseException getParseException() { return parseException; }
221
 
    public String getSpiceText() { return spiceText; }
 
251
    public Code getCode() {
 
252
        return code;
 
253
    }
 
254
 
 
255
    public boolean isJava() {
 
256
        return code == Code.JAVA;
 
257
    }
 
258
 
 
259
    public String getExpr() {
 
260
        return expr;
 
261
    }
 
262
 
 
263
    public Set<Variable.Key> dependsOn() {
 
264
        return depends;
 
265
    }
 
266
 
 
267
    public EvalSpice.ParseException getParseException() {
 
268
        return parseException;
 
269
    }
 
270
 
 
271
    public String getSpiceText() {
 
272
        return spiceText;
 
273
    }
 
274
 
222
275
    public String getHSpiceText(boolean inPar) {
223
276
        return dependsOnEverything ? null : inPar ? spiceTextPar : spiceText;
224
277
    }
225
 
    public String getVerilogText() { return spiceText; }
 
278
 
 
279
    public String getVerilogText() {
 
280
        return spiceText;
 
281
    }
 
282
 
226
283
    public Object eval() {
227
 
        if (parseException != null)
 
284
        if (parseException != null) {
228
285
            return parseException.getMessage();
 
286
        }
229
287
        return exprTree.eval(new EvalContext());
230
288
    }
231
289
 
237
295
    @Override
238
296
    public boolean equals(Object o) {
239
297
        if (o instanceof CodeExpression) {
240
 
            CodeExpression that = (CodeExpression)o;
 
298
            CodeExpression that = (CodeExpression) o;
241
299
            return this.code == that.code && this.expr.equals(that.expr);
242
300
        }
243
301
        return false;
244
302
    }
245
303
 
246
304
    @Override
247
 
    public String toString() { return expr; }
 
305
    public String toString() {
 
306
        return expr;
 
307
    }
248
308
 
249
309
    /**
250
310
     * Write this CodeExpression to IdWriter.
252
312
     */
253
313
    public void write(IdWriter writer) throws IOException {
254
314
        writer.writeString(expr);
255
 
        writer.writeByte((byte)code.ordinal());
 
315
        writer.writeByte((byte) code.ordinal());
256
316
    }
257
317
 
258
318
    /**
275
335
     * @param verbose print all CodeExpressions
276
336
     */
277
337
    public static void printStatistics(boolean verbose) {
278
 
        System.out.println((javaExpressions.size() + spiceExpressions.size() + tclExpressions.size()) +
279
 
                " CodeExpressions after " + numValueOfs + " valueOf calls");
280
 
        if (!verbose) return;
 
338
        System.out.println((javaExpressions.size() + spiceExpressions.size() + tclExpressions.size())
 
339
                + " CodeExpressions after " + numValueOfs + " valueOf calls");
 
340
        if (!verbose) {
 
341
            return;
 
342
        }
281
343
 
282
344
        System.out.println(javaExpressions.size() + " java strings");
283
 
        for (CodeExpression ce: new TreeMap<String,CodeExpression>(javaExpressions).values())
 
345
        for (CodeExpression ce : new TreeMap<String, CodeExpression>(javaExpressions).values()) {
284
346
            printCE(ce);
 
347
        }
285
348
        System.out.println(spiceExpressions.size() + " spice strings");
286
 
        for (CodeExpression ce: new TreeMap<String,CodeExpression>(spiceExpressions).values())
 
349
        for (CodeExpression ce : new TreeMap<String, CodeExpression>(spiceExpressions).values()) {
287
350
            printCE(ce);
 
351
        }
288
352
        System.out.println(tclExpressions.size() + " tcl strings");
289
 
        for (CodeExpression ce: new TreeMap<String,CodeExpression>(tclExpressions).values())
 
353
        for (CodeExpression ce : new TreeMap<String, CodeExpression>(tclExpressions).values()) {
290
354
            printCE(ce);
 
355
        }
291
356
    }
292
357
 
293
358
    private static void printCE(CodeExpression ce) {
294
359
        System.out.print("\"" + ce.getExpr() + "\"\t");
295
 
        if (ce.dependsOnEverything)
 
360
        if (ce.dependsOnEverything) {
296
361
            System.out.print(" ALL");
297
 
        for (Variable.Key varKey: ce.dependsOn())
 
362
        }
 
363
        for (Variable.Key varKey : ce.dependsOn()) {
298
364
            System.out.print(" " + varKey);
299
 
        if (ce.parseException != null)
 
365
        }
 
366
        if (ce.parseException != null) {
300
367
            System.out.print(" ? " + ce.parseException.getMessage());
301
 
        else
 
368
        } else {
302
369
            System.out.print(" -> \"" + ce.spiceText + "\"");
 
370
        }
303
371
        System.out.println();
304
372
    }
305
373
 
306
374
    private static class EvalContext {
307
 
        private Object getDrive() { return null; }
308
 
        private Object subDrive(String instName, String varName) { return null; }
309
 
        private Object get(Variable.Key varKey) { return null; }
 
375
 
 
376
        private Object getDrive() {
 
377
            return null;
 
378
        }
 
379
 
 
380
        private Object subDrive(String instName, String varName) {
 
381
            return null;
 
382
        }
 
383
 
 
384
        private Object get(Variable.Key varKey) {
 
385
            return null;
 
386
        }
310
387
    }
311
388
 
312
389
    private static abstract class Expr {
 
390
 
313
391
        static final int MIN_PRECEDENCE = 1;
314
392
        static final int MAX_PRECEDENCE = EvalSpice.Op.COND.precedence;
315
 
        int numSubExprs() { return 0; }
316
 
        Expr getSubExpr(int i) { throw new IndexOutOfBoundsException(); }
 
393
 
 
394
        int numSubExprs() {
 
395
            return 0;
 
396
        }
 
397
 
 
398
        Expr getSubExpr(int i) {
 
399
            throw new IndexOutOfBoundsException();
 
400
        }
 
401
 
317
402
        void appendText(StringBuilder sb, int outerPrecedence) {
318
403
            if (outerPrecedence < precedence()) {
319
404
                sb.append('(');
323
408
                appendText(sb);
324
409
            }
325
410
        }
 
411
 
326
412
        abstract void appendText(StringBuilder sb);
327
 
        int precedence() { return MIN_PRECEDENCE; }
 
413
 
 
414
        int precedence() {
 
415
            return MIN_PRECEDENCE;
 
416
        }
 
417
 
328
418
        boolean dependsOnEverything() {
329
419
            for (int i = 0; i < numSubExprs(); i++) {
330
 
                if (getSubExpr(i).dependsOnEverything())
 
420
                if (getSubExpr(i).dependsOnEverything()) {
331
421
                    return true;
 
422
                }
332
423
            }
333
424
            return false;
334
425
        }
 
426
 
335
427
        abstract Object eval(EvalContext context);
336
 
        static boolean bool(double d) { return d != 0; }
 
428
 
 
429
        static boolean bool(double d) {
 
430
            return d != 0;
 
431
        }
337
432
    }
338
433
 
339
434
    private static class ConstExpr extends Expr {
 
435
 
340
436
        private final Object value;
341
 
        ConstExpr(Object value) { this.value = value; }
 
437
 
 
438
        ConstExpr(Object value) {
 
439
            this.value = value;
 
440
        }
 
441
 
342
442
        void appendText(StringBuilder sb) {
343
 
            String s = TextUtils.formatDoublePostFix(((Double)value).doubleValue());
 
443
            String s = TextUtils.formatDoublePostFix(((Double) value).doubleValue());
344
444
            sb.append(s);
345
445
        }
346
 
        Object eval(EvalContext context) { return value; }
 
446
 
 
447
        Object eval(EvalContext context) {
 
448
            return value;
 
449
        }
347
450
    }
348
451
 
349
452
    private static class VarExpr extends Expr {
351
454
        private final Variable.Key varKey;
352
455
 
353
456
        VarExpr(Variable.Key varKey) {
354
 
            if (varKey == null)
 
457
            if (varKey == null) {
355
458
                throw new NullPointerException();
 
459
            }
356
460
            this.varKey = varKey;
357
461
        }
358
462
 
359
463
        void appendText(StringBuilder sb) {
360
464
            String name = varKey.getName();
361
 
            if (name.startsWith("ATTR_"))
 
465
            if (name.startsWith("ATTR_")) {
362
466
                name = name.substring(5);
 
467
            }
363
468
            sb.append(name);
364
469
        }
365
470
 
387
492
    }
388
493
 
389
494
    private static class SubDriveExpr extends Expr {
 
495
 
390
496
        private final String instName, varName;
391
497
 
392
498
        SubDriveExpr(String instName, String varName) {
395
501
        }
396
502
 
397
503
        void appendText(StringBuilder sb) {
398
 
            sb.append("LE.subdrive(\"" + instName +"\",\"" + varName + "\")");
 
504
            sb.append("LE.subdrive(\"" + instName + "\",\"" + varName + "\")");
399
505
        }
400
506
 
401
507
        boolean dependsOnEverything() {
408
514
    }
409
515
 
410
516
    private static abstract class UnaryExpr extends Expr {
 
517
 
411
518
        final Expr s;
412
 
        UnaryExpr(Expr s) { this.s = s; }
413
 
        int numSubExprs() { return 1; }
 
519
 
 
520
        UnaryExpr(Expr s) {
 
521
            this.s = s;
 
522
        }
 
523
 
 
524
        int numSubExprs() {
 
525
            return 1;
 
526
        }
 
527
 
414
528
        Expr getSubExpr(int i) {
415
 
            if (i == 0) return s;
 
529
            if (i == 0) {
 
530
                return s;
 
531
            }
416
532
            return super.getSubExpr(i);
417
533
        }
 
534
 
418
535
        Object eval(EvalContext context) {
419
 
            double v = ((Number)s.eval(context)).doubleValue();
 
536
            double v = ((Number) s.eval(context)).doubleValue();
420
537
            return Double.valueOf(apply(v));
421
538
        }
 
539
 
422
540
        abstract double apply(double v);
423
541
    }
424
542
 
425
543
    private static class UnaryOpExpr extends UnaryExpr {
 
544
 
426
545
        private static final String opName = EvalSpice.Op.MINUS.name;
427
546
        private static final int opPrecedence = MIN_PRECEDENCE;
 
547
 
428
548
        UnaryOpExpr(Expr s) {
429
549
            super(s);
430
550
        }
 
551
 
431
552
        void appendText(StringBuilder sb) {
432
553
            sb.append(opName);
433
554
            s.appendText(sb, opPrecedence);
434
555
        }
435
 
        int precedence() { return opPrecedence; }
 
556
 
 
557
        int precedence() {
 
558
            return opPrecedence;
 
559
        }
 
560
 
436
561
        double apply(double v) {
437
562
            return -v;
438
563
        }
439
564
    }
440
565
 
441
566
    private static class UnaryFunExpr extends UnaryExpr {
442
 
        enum Fun { sin, abs, sqrt, int_;
443
 
            @Override public String toString() {
 
567
 
 
568
        enum Fun {
 
569
 
 
570
            sin, abs, sqrt, int_;
 
571
 
 
572
            @Override
 
573
            public String toString() {
444
574
                return this == int_ ? "int" : super.toString();
445
575
            }
446
576
        };
447
577
        private final Fun fun;
 
578
 
448
579
        UnaryFunExpr(Fun fun, Expr s) {
449
580
            super(s);
450
581
            this.fun = fun;
451
582
        }
 
583
 
452
584
        void appendText(StringBuilder sb) {
453
585
            sb.append(fun);
454
586
            sb.append('(');
455
587
            s.appendText(sb, MAX_PRECEDENCE);
456
588
            sb.append(')');
457
589
        }
 
590
 
458
591
        double apply(double v) {
459
592
            switch (fun) {
460
 
                case sin: return Math.sin(v);
461
 
                case abs: return Math.abs(v);
462
 
                case sqrt: return Math.sqrt(v);
463
 
                case int_: return (int)v;
 
593
                case sin:
 
594
                    return Math.sin(v);
 
595
                case abs:
 
596
                    return Math.abs(v);
 
597
                case sqrt:
 
598
                    return Math.sqrt(v);
 
599
                case int_:
 
600
                    return (int) v;
464
601
            }
465
602
            throw new AssertionError();
466
603
        }
467
604
    }
468
605
 
469
606
    private static abstract class BinaryExpr extends Expr {
 
607
 
470
608
        final Expr ls, rs;
471
 
        BinaryExpr(Expr ls, Expr rs) { this.ls = ls; this.rs = rs; }
472
 
        int numSubExprs() { return 2; }
 
609
 
 
610
        BinaryExpr(Expr ls, Expr rs) {
 
611
            this.ls = ls;
 
612
            this.rs = rs;
 
613
        }
 
614
 
 
615
        int numSubExprs() {
 
616
            return 2;
 
617
        }
 
618
 
473
619
        Expr getSubExpr(int i) {
474
 
            if (i == 0) return ls;
475
 
            if (i == 1) return rs;
 
620
            if (i == 0) {
 
621
                return ls;
 
622
            }
 
623
            if (i == 1) {
 
624
                return rs;
 
625
            }
476
626
            return super.getSubExpr(i);
477
627
        }
 
628
 
478
629
        Object eval(EvalContext context) {
479
 
            double lv = ((Double)ls.eval(context)).doubleValue();
480
 
            double rv = ((Double)rs.eval(context)).doubleValue();
 
630
            double lv = ((Double) ls.eval(context)).doubleValue();
 
631
            double rv = ((Double) rs.eval(context)).doubleValue();
481
632
            return Double.valueOf(apply(lv, rv));
482
633
        }
 
634
 
483
635
        abstract double apply(double lv, double rv);
484
636
    }
485
637
 
486
638
    private static class BinaryOpExpr extends BinaryExpr {
 
639
 
487
640
        private final EvalSpice.Op op;
 
641
 
488
642
        BinaryOpExpr(Expr ls, EvalSpice.Op op, Expr rs) {
489
643
            super(ls, rs);
490
644
            this.op = op;
491
645
        }
 
646
 
492
647
        void appendText(StringBuilder sb) {
493
648
            ls.appendText(sb, op.precedence);
494
649
            sb.append(op.name);
495
650
            rs.appendText(sb, op.precedence - 1);
496
651
        }
497
 
        int precedence() { return op.precedence; }
 
652
 
 
653
        int precedence() {
 
654
            return op.precedence;
 
655
        }
 
656
 
498
657
        double apply(double lv, double rv) {
499
 
            if (op == EvalSpice.Op.MULT)  return lv * rv;
500
 
            if (op == EvalSpice.Op.DIV)   return lv / rv;
501
 
            if (op == EvalSpice.Op.PLUS)  return lv + rv;
502
 
            if (op == EvalSpice.Op.MINUS) return lv - rv;
503
 
            if (op == EvalSpice.Op.LT)    return valueOf(lv < rv);
504
 
            if (op == EvalSpice.Op.LTOE)  return valueOf(lv <= rv);
505
 
            if (op == EvalSpice.Op.GT)    return valueOf(lv > rv);
506
 
            if (op == EvalSpice.Op.GTOE)  return valueOf(lv >= rv);
507
 
            if (op == EvalSpice.Op.EQ)    return valueOf(lv == rv);
508
 
            if (op == EvalSpice.Op.NE)    return valueOf(lv != rv);
509
 
            if (op == EvalSpice.Op.LAND)  return valueOf(bool(lv) && bool(rv));
510
 
            if (op == EvalSpice.Op.LOR)   return valueOf(bool(lv) || bool(rv));
 
658
            if (op == EvalSpice.Op.MULT) {
 
659
                return lv * rv;
 
660
            }
 
661
            if (op == EvalSpice.Op.DIV) {
 
662
                return lv / rv;
 
663
            }
 
664
            if (op == EvalSpice.Op.PLUS) {
 
665
                return lv + rv;
 
666
            }
 
667
            if (op == EvalSpice.Op.MINUS) {
 
668
                return lv - rv;
 
669
            }
 
670
            if (op == EvalSpice.Op.LT) {
 
671
                return valueOf(lv < rv);
 
672
            }
 
673
            if (op == EvalSpice.Op.LTOE) {
 
674
                return valueOf(lv <= rv);
 
675
            }
 
676
            if (op == EvalSpice.Op.GT) {
 
677
                return valueOf(lv > rv);
 
678
            }
 
679
            if (op == EvalSpice.Op.GTOE) {
 
680
                return valueOf(lv >= rv);
 
681
            }
 
682
            if (op == EvalSpice.Op.EQ) {
 
683
                return valueOf(lv == rv);
 
684
            }
 
685
            if (op == EvalSpice.Op.NE) {
 
686
                return valueOf(lv != rv);
 
687
            }
 
688
            if (op == EvalSpice.Op.LAND) {
 
689
                return valueOf(bool(lv) && bool(rv));
 
690
            }
 
691
            if (op == EvalSpice.Op.LOR) {
 
692
                return valueOf(bool(lv) || bool(rv));
 
693
            }
511
694
            throw new AssertionError();
512
695
        }
513
 
        private static double valueOf(boolean b) { return b ? 1 : 0; }
 
696
 
 
697
        private static double valueOf(boolean b) {
 
698
            return b ? 1 : 0;
 
699
        }
514
700
    }
515
701
 
516
702
    private static class BinaryFunExpr extends BinaryExpr {
517
 
        enum Fun { min, max };
 
703
 
 
704
        enum Fun {
 
705
 
 
706
            min, max
 
707
        };
518
708
        private final Fun fun;
 
709
 
519
710
        BinaryFunExpr(Fun fun, Expr ls, Expr rs) {
520
711
            super(ls, rs);
521
712
            this.fun = fun;
522
713
        }
 
714
 
523
715
        void appendText(StringBuilder sb) {
524
716
            sb.append(fun);
525
717
            sb.append('(');
528
720
            rs.appendText(sb, MAX_PRECEDENCE);
529
721
            sb.append(')');
530
722
        }
 
723
 
531
724
        double apply(double lv, double rv) {
532
725
            switch (fun) {
533
 
                case min: return Math.min(lv, rv);
534
 
                case max: return Math.max(lv, rv);
 
726
                case min:
 
727
                    return Math.min(lv, rv);
 
728
                case max:
 
729
                    return Math.max(lv, rv);
535
730
            }
536
731
            throw new AssertionError();
537
732
        }
538
733
    }
539
734
 
540
735
    private static class IfThenElseExpr extends Expr {
 
736
 
541
737
        private static final int precedence = MAX_PRECEDENCE;
542
738
        final Expr condS, thenS, elseS;
 
739
 
543
740
        IfThenElseExpr(Expr condS, Expr thenS, Expr elseS) {
544
741
            this.condS = condS;
545
742
            this.thenS = thenS;
546
743
            this.elseS = elseS;
547
744
        }
548
 
        int numSubExprs() { return 3; }
 
745
 
 
746
        int numSubExprs() {
 
747
            return 3;
 
748
        }
 
749
 
549
750
        Expr getSubExpr(int i) {
550
 
            if (i == 0) return condS;
551
 
            if (i == 1) return thenS;
552
 
            if (i == 2) return elseS;
 
751
            if (i == 0) {
 
752
                return condS;
 
753
            }
 
754
            if (i == 1) {
 
755
                return thenS;
 
756
            }
 
757
            if (i == 2) {
 
758
                return elseS;
 
759
            }
553
760
            return super.getSubExpr(i);
554
761
        }
 
762
 
555
763
        void appendText(StringBuilder sb) {
556
764
            condS.appendText(sb, precedence - 1);
557
765
            sb.append('?');
559
767
            sb.append(':');
560
768
            elseS.appendText(sb, precedence);
561
769
        }
562
 
        int precedence() { return MAX_PRECEDENCE; }
 
770
 
 
771
        int precedence() {
 
772
            return MAX_PRECEDENCE;
 
773
        }
 
774
 
563
775
        Object eval(EvalContext context) {
564
 
            boolean condV = bool(((Double)condS.eval(context)).doubleValue());
565
 
            double v = ((Double)(condV ? thenS : elseS).eval(context)).doubleValue();
 
776
            boolean condV = bool(((Double) condS.eval(context)).doubleValue());
 
777
            double v = ((Double) (condV ? thenS : elseS).eval(context)).doubleValue();
566
778
            return Double.valueOf(v);
567
779
        }
568
780
    }
572
784
    }
573
785
 
574
786
    static class ParseSpice_ {
 
787
 
575
788
        private String expr;
576
789
        private boolean isJava;
577
790
        private StringReader reader;
616
829
                    case '(':
617
830
                        throw new EvalSpice.ParseException("Two operands with no operator");
618
831
                    default:
619
 
                        throw new EvalSpice.ParseException("Unexpected character " + (char)tokenizer.ttype);
 
832
                        throw new EvalSpice.ParseException("Unexpected character " + (char) tokenizer.ttype);
620
833
                }
621
834
            } catch (IOException e) {
622
835
                throw new EvalSpice.ParseException(e.getMessage());
623
836
            } catch (EvalSpice.ParseException e) {
624
837
                try {
625
838
                    long left = reader.skip(Long.MAX_VALUE);
626
 
                    int pos = expr.length() - (int)left;
 
839
                    int pos = expr.length() - (int) left;
627
840
                    throw new EvalSpice.ParseException(expr.substring(0, pos) + "<" + e.getMessage() + ">" + expr.substring(pos));
628
 
                } catch (IOException e2) {}
 
841
                } catch (IOException e2) {
 
842
                }
629
843
            }
630
844
            throw new AssertionError();
631
845
        }
656
870
            } else if (tokenizer.ttype == StreamTokenizer.TT_WORD) {
657
871
                e = parseWord();
658
872
            } else if (tokenizer.ttype == '@') {
659
 
                if (nextToken() != StreamTokenizer.TT_WORD)
 
873
                if (nextToken() != StreamTokenizer.TT_WORD) {
660
874
                    throw new EvalSpice.ParseException("Bad name after @");
 
875
                }
661
876
                e = new VarExpr(Variable.newKey("ATTR_" + tokenizer.sval));
662
877
                nextToken();
663
878
            } else if (op != null) {
664
 
                throw new EvalSpice.ParseException("Operator "+op+" with no left hand operand");
 
879
                throw new EvalSpice.ParseException("Operator " + op + " with no left hand operand");
665
880
            } else {
666
881
                throw new EvalSpice.ParseException("Expected identifier");
667
882
            }
668
 
            if (unaryMinus)
 
883
            if (unaryMinus) {
669
884
                e = new UnaryOpExpr(e);
 
885
            }
670
886
 
671
887
            for (;;) {
672
 
                if (op == null || outerPrecedence < op.precedence)
 
888
                if (op == null || outerPrecedence < op.precedence) {
673
889
                    return e;
 
890
                }
674
891
                if (op == EvalSpice.Op.COND) {
675
892
                    nextToken();
676
893
                    Expr thenE = evalEq(Expr.MAX_PRECEDENCE - 1);
712
929
                }
713
930
                if (tt == StreamTokenizer.TT_NUMBER) {
714
931
                    double exp = tokenizer.nval;
715
 
                    if (minus) exp = -1.0 * exp;
 
932
                    if (minus) {
 
933
                        exp = -1.0 * exp;
 
934
                    }
716
935
                    val = val * Math.pow(10, exp);
717
936
                } else {
718
937
                    throw new EvalSpice.ParseException("Invalid token");
719
938
                }
720
 
            }
721
 
            else if (tt == StreamTokenizer.TT_WORD) {
 
939
            } else if (tt == StreamTokenizer.TT_WORD) {
722
940
                if (tokenizer.sval.equalsIgnoreCase("g")) {
723
941
                    val = val * 1e9;
724
942
                } else if (tokenizer.sval.equalsIgnoreCase("meg")) {
735
953
                    val = val * 1e-12;
736
954
                } else if (tokenizer.sval.equalsIgnoreCase("f")) {
737
955
                    val = val * 1e-15;
738
 
                } else
 
956
                } else {
739
957
                    throw new EvalSpice.ParseException("Invalid token");
740
 
            }
741
 
            else {
 
958
                }
 
959
            } else {
742
960
                tokenizer.pushBack();
743
961
            }
744
962
            tokenizer.wordChars('e', 'e');
751
969
            assert tokenizer.ttype == StreamTokenizer.TT_WORD;
752
970
            String id = tokenizer.sval;
753
971
            for (UnaryFunExpr.Fun fun : UnaryFunExpr.Fun.class.getEnumConstants()) {
754
 
                if (!id.equalsIgnoreCase(fun.toString()) && !id.equals("Math." + fun.toString())) continue;
 
972
                if (!id.equalsIgnoreCase(fun.toString()) && !id.equals("Math." + fun.toString())) {
 
973
                    continue;
 
974
                }
755
975
                nextToken();
756
976
                expect('(');
757
977
                Expr arg = evalEq();
759
979
                return new UnaryFunExpr(fun, arg);
760
980
            }
761
981
            for (BinaryFunExpr.Fun fun : BinaryFunExpr.Fun.class.getEnumConstants()) {
762
 
                if (!id.equalsIgnoreCase(fun.toString()) && !id.equals("Math." + fun.toString())) continue;
 
982
                if (!id.equalsIgnoreCase(fun.toString()) && !id.equals("Math." + fun.toString())) {
 
983
                    continue;
 
984
                }
763
985
                nextToken();
764
986
                expect('(');
765
987
                Expr arg1 = evalEq();
768
990
                expect(')');
769
991
                return new BinaryFunExpr(fun, arg1, arg2);
770
992
            }
771
 
            if (/*isJava &&*/ id.equals("P")) {
 
993
            if (/*isJava &&*/id.equals("P")) {
772
994
                nextToken();
773
995
                expect('(');
774
 
                if (tokenizer.ttype != '"')
 
996
                if (tokenizer.ttype != '"') {
775
997
                    throw new EvalSpice.ParseException("Bad name after @");
 
998
                }
776
999
                Variable.Key varKey = Variable.newKey(tokenizer.sval);
777
1000
                nextToken();
778
1001
                expect(')');
787
1010
            if (isJava && id.equals("LE.subdrive")) {
788
1011
                nextToken();
789
1012
                expect('(');
790
 
                if (tokenizer.ttype != '"')
 
1013
                if (tokenizer.ttype != '"') {
791
1014
                    throw new EvalSpice.ParseException("Bad name after subdrive");
 
1015
                }
792
1016
                String instName = tokenizer.sval;
793
1017
                nextToken();
794
1018
                expect(',');
795
 
                if (tokenizer.ttype != '"')
 
1019
                if (tokenizer.ttype != '"') {
796
1020
                    throw new EvalSpice.ParseException("Bad name after subdrive");
 
1021
                }
797
1022
                String varName = tokenizer.sval;
798
1023
                nextToken();
799
1024
                expect(')');
805
1030
        }
806
1031
 
807
1032
        private void expect(int token) throws IOException, EvalSpice.ParseException {
808
 
            if (tokenizer.ttype != token)
809
 
                throw new EvalSpice.ParseException("Expected token "+(char)token);
 
1033
            if (tokenizer.ttype != token) {
 
1034
                throw new EvalSpice.ParseException("Expected token " + (char) token);
 
1035
            }
810
1036
            nextToken();
811
1037
        }
812
1038
 
826
1052
                    break;
827
1053
                case '<':
828
1054
                    op = EvalSpice.Op.LT;
829
 
                    if (tokenizer.nextToken() == '=')
 
1055
                    if (tokenizer.nextToken() == '=') {
830
1056
                        op = EvalSpice.Op.LTOE;
831
 
                    else
 
1057
                    } else {
832
1058
                        tokenizer.pushBack();
 
1059
                    }
833
1060
                    break;
834
1061
                case '>':
835
1062
                    op = EvalSpice.Op.GT;
836
 
                    if (tokenizer.nextToken() == '=')
 
1063
                    if (tokenizer.nextToken() == '=') {
837
1064
                        op = EvalSpice.Op.GTOE;
838
 
                    else
 
1065
                    } else {
839
1066
                        tokenizer.pushBack();
 
1067
                    }
840
1068
                    break;
841
1069
                case '=':
842
1070
                    op = EvalSpice.Op.EQ;
843
 
                    if (tokenizer.nextToken() != '=')
 
1071
                    if (tokenizer.nextToken() != '=') {
844
1072
                        throw new EvalSpice.ParseException("Expected token ==");
 
1073
                    }
845
1074
                    break;
846
1075
                case '!':
847
1076
                    op = EvalSpice.Op.NE;
848
 
                     if (tokenizer.nextToken() != '=')
 
1077
                    if (tokenizer.nextToken() != '=') {
849
1078
                        throw new EvalSpice.ParseException("Expected token !=");
 
1079
                    }
850
1080
                    break;
851
1081
                case '?':
852
1082
                    op = EvalSpice.Op.COND;
865
1095
                    op = null;
866
1096
                    break;
867
1097
                default:
868
 
                    throw new EvalSpice.ParseException("Illegal character " + (char)tokenizer.ttype);
 
1098
                    throw new EvalSpice.ParseException("Illegal character " + (char) tokenizer.ttype);
869
1099
            }
870
1100
            return tokenizer.ttype;
871
1101
        }