-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathdraw_tree.c
164 lines (142 loc) · 5.86 KB
/
draw_tree.c
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
/*******************************************************************************
* print_tree.c: this file is for drawing the abstract syntax tree.
* libast: C library for evaluating expressions with the abstract syntax tree.
* Github repository:
https://github.com/cheng-zhao/libast
* Copyright (c) 2020 Cheng Zhao <zhaocheng03@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*******************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include "libast.h"
/* Tagged union for variables with different data types. */
typedef struct {
int dtype;
union {
bool bval; int ival; long lval; float fval; double dval;
struct ast_string_struct_t { size_t len; char *str; } sval;
} v;
} ast_var_t;
/* The abstract syntax tree (AST). */
typedef struct ast_tree_struct {
int type; /* type of the token */
ast_var_t value; /* value of the token */
const char *ptr; /* poisition in the expression */
struct ast_tree_struct *parent; /* parent node */
struct ast_tree_struct *left; /* left child node */
struct ast_tree_struct *right; /* right child node */
} ast_node_t;
/* Symbols for the tokens. */
const char *token[] = { "NULL", "NUM", "STR", "VAR", "(", ")", "abs", "sqrt",
"ln", "log", "isfinite", "-", "!", "~", "**", "*", "/", "%", "+", "-", "<<",
">>", "<", "<=", ">", ">=", "==", "!=", "&", "^", "|", "&&", "||" };
/* Print the error message and exit. */
#define PRINT_ERROR(ast) { \
ast_perror(ast, stderr, "\x1B[31;1mError:\x1B[0m"); \
ast_destroy(ast); \
return 1; \
}
/* Print the token for a node of the abstract syntax tree. */
void print_node(const ast_t *ast, const ast_node_t *node) {
if (node->type == 1) { /* AST_TOK_NUM */
printf("\x1B[31;1m");
switch (node->value.dtype) {
case AST_DTYPE_BOOL:
if (node->value.v.bval) printf("TRUE");
else printf("FALSE");
break;
case AST_DTYPE_INT: printf("%d", node->value.v.ival); break;
case AST_DTYPE_LONG: printf("%ld", node->value.v.lval); break;
case AST_DTYPE_FLOAT: printf("%g", node->value.v.fval); break;
case AST_DTYPE_DOUBLE: printf("%.8g", node->value.v.dval); break;
default: printf("???"); break;
}
printf("\x1B[0m\n");
}
else if (node->type == 2) { /* AST_TOK_STRING */
printf("\x1B[35;1m%.*s\x1B[0m\n",
(int) node->value.v.sval.len, node->value.v.sval.str);
}
else if (node->type == 3) { /* AST_TOK_VAR */
if (ast->vidx[node->value.v.lval] < 10)
printf("\x1B[36;1m%c%ld\x1B[0m\n", AST_VAR_FLAG,
ast->vidx[node->value.v.lval]);
else
printf("\x1B[36;1m%c%c%ld%c\x1B[0m\n", AST_VAR_FLAG, AST_VAR_START,
node->value.v.lval, AST_VAR_END);
}
else if (node->type <= 30) { /* operators */
printf("\x1B[33;1m%s\x1B[0m\n", token[node->type]);
}
else {
printf("???\n");
}
}
/* Print the tree stucture, with at most 64 levels. */
void print_tree(const ast_t *ast, const ast_node_t *node, int level,
uint64_t path) {
if (!node || level >= 64) return;
int i;
uint64_t s = path;
/* The bits of `path` are used as the indicator of the traversal path. */
for (i = 0; i < level - 1; i++) {
if (s & 1) printf(" "); /* 1 for right child */
else printf("| "); /* 0 for left child */
s >>= 1;
}
if (i < level) {
if (s & 1) printf("`-- ");
else printf("|-- ");
}
print_node(ast, node);
if (!node->right) print_tree(ast, node->left, level + 1, path | 1 << level);
else {
print_tree(ast, node->left, level + 1, path);
print_tree(ast, node->right, level + 1, path | 1 << level);
}
}
int main(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "Usage: %s DTYPE EXPRESSION.\n\
Supported DTYPE: BOOL, INT, LONG, FLOAT, DOUBLE\n", argv[0]);
return 1;
}
/* Determine the data type. */
ast_dtype_t dtype;
if (!strncmp(argv[1], "BOOL", 5)) dtype = AST_DTYPE_BOOL;
else if (!strncmp(argv[1], "INT", 4)) dtype = AST_DTYPE_INT;
else if (!strncmp(argv[1], "LONG", 5)) dtype = AST_DTYPE_LONG;
else if (!strncmp(argv[1], "FLOAT", 6)) dtype = AST_DTYPE_FLOAT;
else if (!strncmp(argv[1], "DOUBLE", 7)) dtype = AST_DTYPE_DOUBLE;
else {
fprintf(stderr, "Supported DTYPE: BOOL, INT, LONG, FLOAT, DOUBLE\n");
return 1;
}
/* Initialise the interface. */
ast_t *ast = ast_init();
if (!ast) PRINT_ERROR(ast);
/* Construct the tree. */
if (ast_build(ast, argv[2], dtype, false)) PRINT_ERROR(ast);
/* Print the tree. */
ast_node_t *tree = (ast_node_t *) ast->ast;
print_tree(ast, tree, 0, 0);
/* Release memory. */
ast_destroy(ast);
return 0;
}