cfad47cfa3/t3compiler/tads3/test/data/calc2.t

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
#include "tads.h"
2
#include "t3.h"
3
#include "dict.h"
4
#include "gramprod.h"
5
#include "tok.h"
6
#include "bignum.h"
7
8
enum token tokOp;
9
enum token tokFloat;
10
11
dictionary gDict;
12
dictionary property funcName;
13
14
/*
15
 *   Calc globals 
16
 */
17
calcGlobals: object
18
    /* 
19
     *   input precision - for any number entered with smaller precision,
20
     *   we'll increase the precision to this value 
21
     */
22
    inputPrecision = 8
23
24
    /* guard digits added to input precision */
25
    guardPrecision = 3
26
27
    /* number of fractional digits to display for each value */
28
    dispFracDigits = 8
29
30
    /* maximum number of digits to display for each value */
31
    dispMaxDigits = 32
32
    
33
    /* display in scientific notation */
34
    dispSci = nil
35
;
36
37
38
/*
39
 *   Custom tokenizer for arithmetic expressions
40
 */
41
CalcTokenizer: Tokenizer
42
    rules_ =
43
    [
44
        /* skip whitespace */
45
        ['[ \t]+', nil, tokCvtSkip, nil],
46
47
        /* numbers */
48
        ['(%.[0-9]+|[0-9]+(%.[0-9]*)?)([eE][+-]?[0-9]+)?',
49
         tokFloat, nil, nil],
50
51
        /* operators */
52
        ['[(+*-/)!^?]', tokOp, nil, nil],
53
54
        /* words */
55
        ['[a-zA-Z]+', tokWord, &tokCvtLower, nil]
56
    ]
57
;
58
59
grammar term: term->val1_ '+' atomic->val2_: object
60
    eval() { return val1_.eval() + val2_.eval(); }
61
;
62
63
grammar term: atomic->val_: object
64
    eval() { return val_.eval(); }
65
;
66
67
grammar atomic: number->num_ : object
68
    eval() { return num_.eval(); }
69
;
70
71
grammar atomic: '(' term->val_ ')' : object
72
    eval() { return val_.eval(); }
73
;
74
75
grammar number: tokFloat->num_ : object
76
    eval()
77
    {
78
        local val;
79
80
        /* parse the number */
81
        val = new BigNumber(num_);
82
83
        /* if the precision is smaller than the input minimum, increase it */
84
        if (val.getPrecision()
85
            < calcGlobals.inputPrecision + calcGlobals.guardPrecision)
86
            val = val.setPrecision(calcGlobals.inputPrecision
87
                                   + calcGlobals.guardPrecision);
88
89
        /* return the value */
90
        return val;
91
    }
92
;
93
94
main(args)
95
{
96
    "T3 Scientific Calculator\n
97
    Type ?\ for help, type Q or QUIT to quit.\n";
98
    
99
    for (;;)
100
    {
101
        local str, toks;
102
        local match;
103
104
        /* read a line */
105
        "\b>";
106
        str = inputLine();
107
108
        /* tokenize the string */
109
        try
110
        {
111
            toks = CalcTokenizer.tokenize(str);
112
        }
113
        catch (TokErrorNoMatch err)
114
        {
115
            "Invalid character '<<err.remainingStr_.substr(1, 1)>>'\n";
116
            continue;
117
        }
118
119
        /* if it's 'quit' or 'q', stop */
120
        if (toks.length() == 1
121
            && (getTokVal(toks[1]) is in('q', 'quit')))
122
            break;
123
124
        /* if it's '?', show help */
125
        if (toks.length() == 1
126
            && (getTokVal(toks[1]) == '?'))
127
        {
128
            showHelp();
129
            continue;
130
        }
131
132
        /* parse it */
133
        match = term.parseTokens(toks, gDict);
134
135
        /* if we didn't get anything, say so */
136
        if (match.length() == 0)
137
        {
138
            "Invalid expression\n";
139
        }
140
        else
141
        {
142
            local val;
143
            local flags;
144
            
145
            /* evaluate the expression */
146
            val = match[1][2].eval();
147
            if (val != nil)
148
            {
149
                /* clear the display flags */
150
                flags = 0;
151
                
152
                /* display in scientific or normal notation as desired */
153
                if (calcGlobals.dispSci)
154
                    flags |= BignumExp;
155
                
156
                /* display the value */                
157
                "<<val.formatString(calcGlobals.dispMaxDigits, flags,
158
                                    -1, calcGlobals.dispFracDigits)>>\n";
159
            }
160
        }
161
    }
162
}
163
164
showHelp()
165
{
166
    "Enter numbers in decimal or scientific notation:\b
167
    \t3.1415926\n
168
    \t1.705e-11\b
169
    Operators, in order of precedence:\b
170
    \ta ^ b\t\traise a to the power of b\n
171
    \ta * b\t\tmultiply\n
172
    \ta / b\t\tdivide\n
173
    \ta + b\t\tadd\n
174
    \ta - b\t\tsubtract\n
175
    \t( a )\t\toverride operator precedence\n
176
    \b
177
    Functions:\b
178
    \tsin(x)\t\ttrigonometric sine\n
179
    \tcos(x)\t\ttrigonometric cosine\n
180
    \ttan(x)\t\ttrigonometric tangent\n
181
    \tln(x)\t\tnatural logarithm\n
182
    \tlog(x)\t\tcommon (base-10) logarithm\n
183
    \texp(x)\t\traise e (the base of the natural logarithm) to power\n
184
    \b
185
    Constants:\b
186
    \tpi\t\t3.14159265\n
187
    \te\t\t2.7182818\n
188
    \b";
189
    "Commands:\b
190
    \tquit\t\tturn off the calculator\n
191
    \tsci N\t\tdisplay scientific notation with N digits after the decimal\n
192
    \tfix N\t\tdisplay fixed notation with N digits after the decimal\n
193
    \tprec N\t\tset default input precision to N digits\n
194
    \b";
195
}
196