-
Notifications
You must be signed in to change notification settings - Fork 6
/
placeholder.c
160 lines (128 loc) · 3.11 KB
/
placeholder.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
/*
placeholder.c
SuperCalc
Created by C0deH4cker on 8/31/15.
Copyright (c) 2015 C0deH4cker. All rights reserved.
*/
#include "placeholder.h"
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <errno.h>
#include "support.h"
#include "generic.h"
#include "error.h"
static PLACETYPE getPlaceholderType(char type);
static PLACETYPE getPlaceholderType(char type) {
switch(type) {
case 'i': return PH_INT;
case 'r': return PH_REAL;
case 'f': return PH_FRAC;
case 'x': return PH_EXPR;
case 'u': return PH_UNARY;
case 'c': return PH_CALL;
case 'n': return PH_VAR;
case 'v': return PH_VEC;
case '@': return PH_VAL;
default: return PH_ERR;
}
}
Placeholder* Placeholder_new(PLACETYPE type, unsigned index) {
Placeholder* ret = fmalloc(sizeof(*ret));
ret->type = type;
ret->index = index;
return ret;
}
Placeholder* Placeholder_create(char type, unsigned index) {
return Placeholder_new(getPlaceholderType(type), index);
}
Placeholder* Placeholder_fromString(const char* fmt) {
return Placeholder_parse(&fmt);
}
/* Destructor */
void Placeholder_free(Placeholder* ph) {
destroy(ph);
}
/* Copying */
Placeholder* Placeholder_copy(const Placeholder* ph) {
return Placeholder_new(ph->type, ph->index);
}
/* Parse a placeholder from a format string */
Placeholder* Placeholder_parse(const char** expr) {
if(**expr != '@') {
RAISE(badChar(*expr), true);
}
/* Move past '@' */
(*expr)++;
unsigned index = 0;
if(isdigit(**expr)) {
/* Like @1v or @4@ */
char* end;
errno = 0;
/* Read the number after the '@' */
index = (unsigned)strtoul(*expr, &end, 10);
if(errno != 0 || index == 0 || *expr == end) {
/* An error occurred (EINVAL, ERANGE) */
RAISE(syntaxError(*expr, "Invalid number in placeholder"), true);
}
/* Advance past the number */
*expr = end;
}
PLACETYPE type = getPlaceholderType(**expr);
if(type == PH_ERR) {
RAISE(badChar(*expr), true);
}
(*expr)++;
return Placeholder_new(type, index);
}
/* Get the format character for the specified Value type */
static char getFormatChar(PLACETYPE type) {
switch(type) {
case PH_INT: return 'i';
case PH_REAL: return 'r';
case PH_FRAC: return 'f';
case PH_EXPR: return 'x';
case PH_UNARY: return 'u';
case PH_CALL: return 'c';
case PH_VAR: return 'n';
case PH_VEC: return 'v';
case PH_VAL: return '@';
default: return '\0';
}
}
/* Printing */
char* Placeholder_repr(const Placeholder* ph) {
char* ret;
if(ph->index > 0) {
asprintf(&ret, "@%u%c", ph->index, getFormatChar(ph->type));
}
else {
asprintf(&ret, "@%c", getFormatChar(ph->type));
}
return ret;
}
char* Placeholder_xml(const Placeholder* ph, unsigned indent) {
UNREFERENCED_PARAMETER(indent);
/*
"@1i^(1/2)"
<pow>
<placeholder type="i" index="1"/>
<div>
<int>1</int>
<int>2</int>
</div>
</pow>
*/
char* ret;
if(ph->index > 0) {
asprintf(&ret,
"<placeholder type=\"%c\" index=\"%u\"/>",
getFormatChar(ph->type), ph->index);
}
else {
asprintf(&ret,
"<placeholder type=\"%c\"/>",
getFormatChar(ph->type));
}
return ret;
}