-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparse.y
173 lines (143 loc) · 3.83 KB
/
parse.y
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
%{
/*
* This file is licensed under BSD 3-Clause.
* All license information is available in the included COPYING file.
*/
/*
* parse.y
*
* Author : Finn Rayment <[email protected]>
* Date created : 21/07/2022
*/
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "incl.h"
#define EQ_INTEGER 1
#define EQ_POINT 2
#define EQ_FRACTION 3
#define V_PI 3.14159265358979323846
#define V_E 2.71828182845904523536
#define V_RAD 0.0174532925199
#define V_DEG 57.2957795131
int yylex(void);
void yyerror(char *, ...);
int yyrunning = 1;
int yyended = 1;
extern int argv_redirect;
#ifdef DEBUG
int yydebug = 1;
#endif /* DEBUG */
int c, i, j, k;
long long ll;
char fstr[128];
%}
%token NUMBER EXIT END LINEEND LPAREN RPAREN COMMA
%token PLUS MINUS MULTIPLY DIVIDE EXPONENT MODULO EXPONENTIAL
%token PI E
%token SIN COS TAN ASIN ACOS ATAN ATAN2
%token DEG RAD
%token SQRT CBRT
%token LOG2 LOG10 LOG LN
/* associativity */
%left PLUS MINUS
%left MODULO
%left MULTIPLY DIVIDE
%left EXPONENT
%left EXPONENTIAL
%start unit_list
%%
unit_list: unit unit_list
| unit
| EXIT { yyrunning = 0; yyended = 0; YYACCEPT; }
| END { yyrunning = 0; yyended = 1; YYACCEPT; }
| LINEEND { yyrunning = 0; yyended = 1; YYACCEPT; }
;
unit: equation {
/* a simple 3-state machine to find the last significant digit
and crop anything that remains -- */
i = 0;
j = EQ_INTEGER;
k = -1;
snprintf(fstr, 128, "%f", $1);
while ((c = *(fstr+i)) && i < 128)
{
if (c == '.')
j = EQ_POINT;
else if (j == EQ_POINT && c >= '0' && c <= '9')
j = EQ_FRACTION;
else if (j == EQ_INTEGER)
k = i;
/* advance the significant digit */
if (j == EQ_FRACTION && c > '0' && c <= '9')
k = i;
++i;
}
/* perform the crop */
if (k >= 0)
*(fstr+k+1) = '\0';
/* now print the answer */
fprintf(stdout, " = %s\n", fstr);
if (yyended && !argv_redirect)
fputc('\n', stdout);
/* kill the parser because we only want to parse one line at a time */
YYACCEPT;
}
;
equation: expr END { $$ = $1; yyended = 1; }
| expr LINEEND { $$ = $1; yyended = 0; }
;
expr: add_expr
;
add_expr: mul_expr { $$ = $1; }
| add_expr PLUS mul_expr { $$ = $1 + $3; }
| add_expr MINUS mul_expr { $$ = $1 - $3; }
;
mul_expr: pow_expr { $$ = $1; }
| mul_expr MULTIPLY pow_expr { $$ = $1 * $3; }
| mul_expr DIVIDE pow_expr { $$ = $1 / $3; }
;
pow_expr: mod_expr { $$ = $1; }
| pow_expr EXPONENT mod_expr { $$ = pow($1, $3); }
;
mod_expr: unary_expr { $$ = $1; }
| mod_expr MODULO unary_expr { $$ = (int) $1 % (int) $3; }
;
unary_expr: exp_expr { $$ = $1; }
| MINUS exp_expr { $$ = -$2; }
;
exp_expr: func_expr_2 { $$ = $1; }
| func_expr_2 EXPONENTIAL {
i = ll = (int) $1;
while (--i > 1)
ll *= i;
$$ = ll;
}
;
func_expr_2: LOG primary COMMA primary { $$ = log($2) / log($4); }
| LOG LPAREN primary COMMA primary RPAREN { $$ = log($3) / log($5); }
| ATAN2 primary COMMA primary { $$ = atan2($2, $4); }
| ATAN2 LPAREN primary COMMA primary RPAREN { $$ = atan2($3, $5); }
| func_expr { $$ = $1; }
;
func_expr: primary { $$ = $1; }
| SIN primary { $$ = sin($2); }
| COS primary { $$ = cos($2); }
| TAN primary { $$ = tan($2); }
| ASIN primary { $$ = asin($2); }
| ACOS primary { $$ = acos($2); }
| ATAN primary { $$ = atan($2); }
| SQRT primary { $$ = sqrt($2); }
| CBRT primary { $$ = cbrt($2); }
| LOG2 primary { $$ = log2($2); }
| LOG10 primary { $$ = log10($2); }
| LN primary { $$ = log($2); }
| DEG primary { $$ = $2 * V_DEG; }
| RAD primary { $$ = $2 * V_RAD; }
;
primary: NUMBER { $$ = $1; }
| PI { $$ = V_PI; }
| E { $$ = V_E; }
| LPAREN expr RPAREN { $$ = $2; }
;
%%