mathematical 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +20 -9
- data/Rakefile +5 -24
- data/ext/mathematical/extconf.rb +8 -3
- data/ext/mathematical/lasem/src/lsmdomparser.c +7 -7
- data/ext/mathematical/lasem/src/lsmdomparser.h +2 -2
- data/ext/mathematical/lasem/src/lsmitex.c +8 -5
- data/ext/mathematical/lasem/src/lsmitex.h +1 -1
- data/ext/mathematical/lasem/src/lsmmathmldocument.c +2 -2
- data/ext/mathematical/lasem/src/lsmmathmldocument.h +1 -1
- data/ext/mathematical/lasem/tests/lsmtest.c +2 -2
- data/ext/mathematical/mathematical.c +119 -10
- data/ext/mathematical/mtex2MML/ext/extconf.rb +4 -0
- data/ext/mathematical/mtex2MML/src/lex.yy.c +6791 -0
- data/ext/mathematical/mtex2MML/src/mtex2MML.h +59 -0
- data/ext/mathematical/mtex2MML/src/parse_extras.c +306 -0
- data/ext/mathematical/mtex2MML/src/parse_extras.h +78 -0
- data/ext/mathematical/mtex2MML/src/stack.c +80 -0
- data/ext/mathematical/mtex2MML/src/stack.h +101 -0
- data/ext/mathematical/mtex2MML/src/string_extras.c +211 -0
- data/ext/mathematical/mtex2MML/src/string_extras.h +46 -0
- data/ext/mathematical/mtex2MML/src/y.tab.c +7090 -0
- data/ext/mathematical/mtex2MML/src/y.tab.h +393 -0
- data/lib/mathematical.rb +1 -0
- data/lib/mathematical/corrections.rb +34 -0
- data/lib/mathematical/render.rb +21 -12
- data/lib/mathematical/version.rb +1 -1
- data/mathematical.gemspec +2 -2
- data/test/mathematical/corrections_test.rb +56 -0
- data/test/mathematical/fixtures/png/pmatrix.png +0 -0
- data/test/mathematical/fixtures_test.rb +11 -1
- data/test/mathematical/maliciousness_test.rb +10 -2
- data/test/mathematical/mathml_test.rb +22 -0
- data/test/mathematical/png_test.rb +26 -0
- data/test/test_helper.rb +13 -0
- metadata +150 -134
- data/ext/mathematical/itexToMML/itex2MML.h +0 -63
- data/ext/mathematical/itexToMML/lex.yy.c +0 -6548
- data/ext/mathematical/itexToMML/y.tab.c +0 -6179
- data/ext/mathematical/itexToMML/y.tab.h +0 -389
@@ -0,0 +1,59 @@
|
|
1
|
+
#ifndef MTEX2MML_H
|
2
|
+
#define MTEX2MML_H
|
3
|
+
|
4
|
+
#define MTEX2MML_VERSION "1.0.0"
|
5
|
+
|
6
|
+
#ifdef __cplusplus
|
7
|
+
extern "C" {
|
8
|
+
#endif
|
9
|
+
|
10
|
+
/* Step 1. Parse a buffer with mtex source; return value is mathml, or 0 on failure (e.g., parse error).
|
11
|
+
*/
|
12
|
+
extern char * mtex2MML_parse (const char * buffer, unsigned long length);
|
13
|
+
|
14
|
+
/* Step 2. Free the string from Step 1.
|
15
|
+
*/
|
16
|
+
extern void mtex2MML_free_string (char * str);
|
17
|
+
|
18
|
+
|
19
|
+
/* Alternatively, to filter generic source and converting embedded equations, use:
|
20
|
+
*/
|
21
|
+
extern int mtex2MML_filter (const char * buffer, unsigned long length);
|
22
|
+
|
23
|
+
extern int mtex2MML_html_filter (const char * buffer, unsigned long length);
|
24
|
+
extern int mtex2MML_strict_html_filter (const char * buffer, unsigned long length);
|
25
|
+
|
26
|
+
|
27
|
+
/* To change output methods:
|
28
|
+
*
|
29
|
+
* Note: If length is 0, then buffer is treated like a string; otherwise only length bytes are written.
|
30
|
+
*/
|
31
|
+
extern void (*mtex2MML_write) (const char * buffer, unsigned long length); /* default writes to stdout */
|
32
|
+
extern void (*mtex2MML_write_mathml) (const char * mathml); /* default calls mtex2MML_write(mathml,0) */
|
33
|
+
extern void (*mtex2MML_error) (const char * msg); /* default writes to stderr */
|
34
|
+
|
35
|
+
|
36
|
+
/* Other stuff:
|
37
|
+
*/
|
38
|
+
extern void mtex2MML_setup (const char * buffer, unsigned long length);
|
39
|
+
|
40
|
+
extern void mtex2MML_restart ();
|
41
|
+
|
42
|
+
extern char * mtex2MML_copy_string (const char * str);
|
43
|
+
extern char * mtex2MML_copy_string_extra (const char * str, unsigned extra);
|
44
|
+
extern char * mtex2MML_copy2 (const char * first, const char * second);
|
45
|
+
extern char * mtex2MML_copy3 (const char * first, const char * second, const char * third);
|
46
|
+
extern char * mtex2MML_copy_escaped (const char * str);
|
47
|
+
|
48
|
+
extern char * mtex2MML_empty_string;
|
49
|
+
|
50
|
+
extern int mtex2MML_lineno;
|
51
|
+
|
52
|
+
extern int mtex2MML_rowposn;
|
53
|
+
extern int mtex2MML_displaymode;
|
54
|
+
|
55
|
+
#ifdef __cplusplus
|
56
|
+
}
|
57
|
+
#endif
|
58
|
+
|
59
|
+
#endif /* ! MTEX2MML_H */
|
@@ -0,0 +1,306 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
#include <string.h>
|
4
|
+
#include "parse_extras.h"
|
5
|
+
#include "string_extras.h"
|
6
|
+
#include "stack.h"
|
7
|
+
|
8
|
+
#ifdef FLIP_OFFSET_VAL
|
9
|
+
#define OFFSET_VAL 0
|
10
|
+
#else
|
11
|
+
#define OFFSET_VAL 1
|
12
|
+
#endif
|
13
|
+
|
14
|
+
void initSymbolDataArray(symbolDataArray *a, size_t initialSize)
|
15
|
+
{
|
16
|
+
// Allocate initial space
|
17
|
+
a->array = (symbolData *)malloc(initialSize * sizeof(symbolData));
|
18
|
+
|
19
|
+
a->used = 0; // no elements used
|
20
|
+
a->size = initialSize; // available number of elements
|
21
|
+
|
22
|
+
// Initialize all elements of the array at once: they are contiguous
|
23
|
+
memset(&a->array[0], 0, sizeof(symbolData) * initialSize);
|
24
|
+
}
|
25
|
+
|
26
|
+
void insertSymbolDataArray(symbolDataArray *a, symbolData element)
|
27
|
+
{
|
28
|
+
if (a->used == a->size) {
|
29
|
+
a->size *= 2;
|
30
|
+
a->array = (symbolData *)realloc(a->array, a->size * sizeof(symbolData));
|
31
|
+
// Initialize the last/new elements of the reallocated array
|
32
|
+
memset(&a->array[a->used],0, sizeof(symbolData) * (a->size - a->used));
|
33
|
+
}
|
34
|
+
|
35
|
+
a->array[a->used].attribute = (char*)malloc(strlen(element.attribute) + 1);
|
36
|
+
strcpy(a->array[a->used].attribute, element.attribute);
|
37
|
+
|
38
|
+
a->array[a->used].offset_pos = element.offset_pos;
|
39
|
+
|
40
|
+
a->used++;
|
41
|
+
}
|
42
|
+
|
43
|
+
void sortSymbolDataArray(symbolDataArray *a) {
|
44
|
+
int i, j, n = a->used;
|
45
|
+
|
46
|
+
for(i = 1; i < n; i++) {
|
47
|
+
for(j = 0; j < n - i; j++) {
|
48
|
+
if(a->array[j].offset_pos < a->array[j+1].offset_pos) {
|
49
|
+
symbolData temp = a->array[j];
|
50
|
+
a->array[j] = a->array[j+1];
|
51
|
+
a->array[j+1] = temp;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
void deleteSymbolDataArray(symbolDataArray *a)
|
58
|
+
{
|
59
|
+
int i;
|
60
|
+
|
61
|
+
// Free all name variables of each array element first
|
62
|
+
for(i = 0; i <a->used; i++)
|
63
|
+
{
|
64
|
+
free(a->array[i].attribute);
|
65
|
+
a->array[i].attribute = NULL;
|
66
|
+
}
|
67
|
+
|
68
|
+
// Now free the array
|
69
|
+
free(a->array);
|
70
|
+
a->array = NULL;
|
71
|
+
|
72
|
+
a->used = 0;
|
73
|
+
a->size = 0;
|
74
|
+
}
|
75
|
+
|
76
|
+
char * env_replacements(const char *string) {
|
77
|
+
stackT array_stack;
|
78
|
+
stackElementT stack_item, last_stack_item;
|
79
|
+
|
80
|
+
char *tok = NULL, *at_top = NULL;
|
81
|
+
char *new_environment = dupe_string(string), *dupe_str = dupe_string(string);
|
82
|
+
char *line = strtok(dupe_str, "\n");
|
83
|
+
char *attr_rowlines = "", *attr_rowspacing = "", *em_str, *temp = "";
|
84
|
+
|
85
|
+
const char *from = "\\begin", *until = "\\end", *hline = "\\hline", *hdashline = "\\hdashline",
|
86
|
+
*line_separator = "\\\\",
|
87
|
+
*em_pattern_begin = "\\[", *em_pattern_end = "]";
|
88
|
+
|
89
|
+
int start = 0, offset = 0, attr_rowlines_len = 0, str_len = 0, i = 0;
|
90
|
+
symbolDataArray hline_data_array;
|
91
|
+
symbolData hline_data;
|
92
|
+
|
93
|
+
symbolDataArray row_spacing_data_array;
|
94
|
+
symbolData row_spacing_data;
|
95
|
+
|
96
|
+
// set up the array stack
|
97
|
+
StackInit(&array_stack, strlen(new_environment));
|
98
|
+
initSymbolDataArray(&hline_data_array, 5);
|
99
|
+
initSymbolDataArray(&row_spacing_data_array, 1);
|
100
|
+
|
101
|
+
// if not an environment, don't bother going on
|
102
|
+
if ((strstr(string, from) == NULL && strstr(string, until) == NULL)) {
|
103
|
+
StackDestroy(&array_stack);
|
104
|
+
deleteSymbolDataArray(&hline_data_array);
|
105
|
+
deleteSymbolDataArray(&row_spacing_data_array);
|
106
|
+
free(dupe_str);
|
107
|
+
|
108
|
+
return string;
|
109
|
+
}
|
110
|
+
|
111
|
+
while (line != NULL) {
|
112
|
+
str_len = strlen(line) + 1;
|
113
|
+
|
114
|
+
stack_item.line = line;
|
115
|
+
stack_item.line_pos = start + 1;
|
116
|
+
|
117
|
+
start += str_len;
|
118
|
+
|
119
|
+
StackPush(&array_stack, stack_item);
|
120
|
+
|
121
|
+
if (strstr(line, until) != NULL) {
|
122
|
+
while (!StackIsEmpty(&array_stack)) {
|
123
|
+
last_stack_item = StackPop(&array_stack);
|
124
|
+
attr_rowlines_len = strlen(attr_rowlines);
|
125
|
+
at_top = strstr(last_stack_item.line, from);
|
126
|
+
|
127
|
+
// we've reached the top, but there looks like there might be some data
|
128
|
+
if (at_top != NULL && strstr(last_stack_item.line, line_separator) == NULL) {
|
129
|
+
break;
|
130
|
+
}
|
131
|
+
|
132
|
+
// looking for a line match
|
133
|
+
if (strstr(last_stack_item.line, hline) != NULL) {
|
134
|
+
if (attr_rowlines_len > 0)
|
135
|
+
remove_last_char(attr_rowlines);
|
136
|
+
attr_rowlines = join(attr_rowlines, "s");
|
137
|
+
}
|
138
|
+
else if (strstr(last_stack_item.line, hdashline) != NULL) {
|
139
|
+
if (attr_rowlines_len > 0)
|
140
|
+
remove_last_char(attr_rowlines);
|
141
|
+
attr_rowlines = join(attr_rowlines, "d");
|
142
|
+
}
|
143
|
+
else {
|
144
|
+
attr_rowlines = join(attr_rowlines, "0");
|
145
|
+
}
|
146
|
+
|
147
|
+
if (strstr(last_stack_item.line, line_separator) != NULL) {
|
148
|
+
if ( (tok = strstr(last_stack_item.line, em_pattern_begin)) != NULL) {
|
149
|
+
temp = tok + 2;
|
150
|
+
if ( (tok = strstr(temp, em_pattern_end)) != NULL) {
|
151
|
+
offset = (int)(tok - temp);
|
152
|
+
em_str = malloc(offset);
|
153
|
+
if (strlen(em_str) != 0) {
|
154
|
+
em_str = dupe_string_n(temp, offset);
|
155
|
+
// MathML always expectes "em" points
|
156
|
+
convertToEm(em_str);
|
157
|
+
row_spacing_data.attribute = em_str;
|
158
|
+
row_spacing_data.offset_pos = -1; // this value is not really important
|
159
|
+
insertSymbolDataArray(&row_spacing_data_array, row_spacing_data);
|
160
|
+
free(em_str);
|
161
|
+
}
|
162
|
+
}
|
163
|
+
}
|
164
|
+
else {
|
165
|
+
row_spacing_data.attribute = "0em";
|
166
|
+
row_spacing_data.offset_pos = -1; // this value is not really important
|
167
|
+
insertSymbolDataArray(&row_spacing_data_array, row_spacing_data);
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
171
|
+
// we've reached the top, so stop.
|
172
|
+
if (at_top != NULL)
|
173
|
+
break;
|
174
|
+
}
|
175
|
+
|
176
|
+
if (attr_rowlines_len != 0) {
|
177
|
+
// array is form of \begin{array}[t]{cc..c}
|
178
|
+
tok = strstr(last_stack_item.line, "]{");
|
179
|
+
if (tok == NULL) {
|
180
|
+
// array is form of \begin{array}{cc..c}
|
181
|
+
tok = strstr(last_stack_item.line, "}{");
|
182
|
+
}
|
183
|
+
if (tok == NULL) {
|
184
|
+
// not an array, but rather, some env, like \begin{cases}
|
185
|
+
tok = strstr(last_stack_item.line, "}");
|
186
|
+
}
|
187
|
+
|
188
|
+
offset = last_stack_item.line_pos + (tok - last_stack_item.line);
|
189
|
+
// we cut the last char because we can skip the first row
|
190
|
+
remove_last_char(attr_rowlines);
|
191
|
+
|
192
|
+
// we reverse the string, because we're going backwards
|
193
|
+
strrev(attr_rowlines);
|
194
|
+
|
195
|
+
// empty rowlines should be reset
|
196
|
+
if (strlen(attr_rowlines) == 0)
|
197
|
+
attr_rowlines = join(attr_rowlines, "0");
|
198
|
+
|
199
|
+
attr_rowlines = join(join("(", attr_rowlines), ")");
|
200
|
+
|
201
|
+
for (i = row_spacing_data_array.used - 1; i >= 0; i--) {
|
202
|
+
attr_rowspacing = join(join(attr_rowspacing, row_spacing_data_array.array[i].attribute), "|");
|
203
|
+
}
|
204
|
+
|
205
|
+
if (strlen(attr_rowspacing) > 0) {
|
206
|
+
if (empty_row_spacings(attr_rowspacing) == 1) {
|
207
|
+
attr_rowspacing = "0.5ex";
|
208
|
+
}
|
209
|
+
else {
|
210
|
+
// last char is a pipe (|)
|
211
|
+
remove_last_char(attr_rowspacing);
|
212
|
+
}
|
213
|
+
|
214
|
+
attr_rowspacing = join(join("<", attr_rowspacing), ">");
|
215
|
+
}
|
216
|
+
|
217
|
+
hline_data.attribute = join(attr_rowspacing, attr_rowlines);
|
218
|
+
hline_data.offset_pos = offset + OFFSET_VAL;
|
219
|
+
insertSymbolDataArray(&hline_data_array, hline_data);
|
220
|
+
}
|
221
|
+
|
222
|
+
attr_rowlines = "";
|
223
|
+
attr_rowspacing = "";
|
224
|
+
attr_rowlines_len = 0;
|
225
|
+
}
|
226
|
+
|
227
|
+
line = strtok(NULL, "\n");
|
228
|
+
}
|
229
|
+
|
230
|
+
// sort array by highest values first, so that we can insert to new_environment from
|
231
|
+
// the bottom to the top (ensuring line numbers don't shift)
|
232
|
+
sortSymbolDataArray(&hline_data_array);
|
233
|
+
|
234
|
+
for (i = 0; i < hline_data_array.used; i++) {
|
235
|
+
insert_substring(&new_environment, hline_data_array.array[i].attribute, hline_data_array.array[i].offset_pos);
|
236
|
+
}
|
237
|
+
|
238
|
+
StackDestroy(&array_stack);
|
239
|
+
deleteSymbolDataArray(&hline_data_array);
|
240
|
+
deleteSymbolDataArray(&row_spacing_data_array);
|
241
|
+
free(dupe_str);
|
242
|
+
|
243
|
+
return new_environment;
|
244
|
+
}
|
245
|
+
|
246
|
+
const char *vertical_pipe_extract(const char *string) {
|
247
|
+
char *orig = dupe_string(string);
|
248
|
+
char *columnlines = "", *previous_column = "";
|
249
|
+
int i = 0;
|
250
|
+
|
251
|
+
if (strncmp(orig, "s", 1) == 0) {
|
252
|
+
columnlines = "frame=\"solid\" columnlines=\"";
|
253
|
+
remove_first_char(orig);
|
254
|
+
}
|
255
|
+
else if (strncmp(orig, "d", 1) == 0) {
|
256
|
+
columnlines = "frame=\"dashed\" columnlines=\"";
|
257
|
+
remove_first_char(orig);
|
258
|
+
}
|
259
|
+
else {
|
260
|
+
columnlines = "columnlines=\"";
|
261
|
+
}
|
262
|
+
|
263
|
+
char *token = strtok(orig, " ");
|
264
|
+
|
265
|
+
while (token != NULL) {
|
266
|
+
if (strncmp(token, "s", 1) == 0) {
|
267
|
+
previous_column = "s";
|
268
|
+
columnlines = join(columnlines, "solid ");
|
269
|
+
}
|
270
|
+
else if (strncmp(token, "d", 1) == 0) {
|
271
|
+
previous_column = "d";
|
272
|
+
columnlines = join(columnlines, "dashed ");
|
273
|
+
}
|
274
|
+
else {
|
275
|
+
if (i >= 1) { // we must skip the first blank col
|
276
|
+
// only if there is no previous border should a border be considered, eg. "cc", not "c|c"
|
277
|
+
if (strncmp(previous_column, "s", 1) != 0 && strncmp(previous_column, "d", 1) != 0) {
|
278
|
+
columnlines = join(columnlines, "none ");
|
279
|
+
}
|
280
|
+
previous_column = "0";
|
281
|
+
}
|
282
|
+
}
|
283
|
+
|
284
|
+
i++;
|
285
|
+
token = strtok(NULL, " ");
|
286
|
+
}
|
287
|
+
|
288
|
+
// an empty string here angers Lasem
|
289
|
+
if (strncmp(columnlines, "columnlines=\"\0", 14) == 0)
|
290
|
+
columnlines = "columnlines=\"none";
|
291
|
+
// an empty space also angers Lasem
|
292
|
+
else
|
293
|
+
remove_last_char(columnlines);
|
294
|
+
|
295
|
+
free(orig);
|
296
|
+
return columnlines;
|
297
|
+
}
|
298
|
+
|
299
|
+
const char *remove_excess_pipe_chars(const char *string) {
|
300
|
+
char *dup = dupe_string(string);
|
301
|
+
|
302
|
+
dup = replace_str(dup, "s", "");
|
303
|
+
dup = replace_str(dup, "d", "");
|
304
|
+
|
305
|
+
return dup;
|
306
|
+
}
|
@@ -0,0 +1,78 @@
|
|
1
|
+
#ifndef PARSE_EXTRAS_H
|
2
|
+
#define PARSE_EXTRAS_H
|
3
|
+
|
4
|
+
#ifdef __cplusplus
|
5
|
+
extern "C" {
|
6
|
+
#endif
|
7
|
+
|
8
|
+
typedef struct {
|
9
|
+
char *attribute;
|
10
|
+
int offset_pos;
|
11
|
+
} symbolData;
|
12
|
+
|
13
|
+
// array of structs
|
14
|
+
typedef struct
|
15
|
+
{
|
16
|
+
symbolData *array;
|
17
|
+
size_t used;
|
18
|
+
size_t size;
|
19
|
+
} symbolDataArray;
|
20
|
+
|
21
|
+
// set up array of symbols (like hlines)
|
22
|
+
extern void initSymbolDataArray(symbolDataArray *a, size_t initialSize);
|
23
|
+
|
24
|
+
// insert into symbol array
|
25
|
+
extern void insertSymbolDataArray(symbolDataArray *a, symbolData element);
|
26
|
+
|
27
|
+
// sort the array based on offset_pos
|
28
|
+
extern void sortSymbolDataArray(symbolDataArray *a);
|
29
|
+
|
30
|
+
// destroyes the array
|
31
|
+
extern void deleteSymbolDataArray(symbolDataArray *a);
|
32
|
+
|
33
|
+
// Move various symbols not easily supported inline with the `\begin` line
|
34
|
+
// This is so that the Bison parser can properly act on these. For example,
|
35
|
+
// `\hline`, `\hlinedash`, or `\\[2ex]` declerations.
|
36
|
+
//
|
37
|
+
// In order to properly address these situations, we need to parse them, find their symbols,
|
38
|
+
// and then modify the starting environment declaration to point out where those symbols are.
|
39
|
+
//
|
40
|
+
// Suppose there is an array like:
|
41
|
+
//
|
42
|
+
// \begin{array}{c:c}
|
43
|
+
// \begin{array}{c|cclc}
|
44
|
+
// \text{min} & 0 & 1 & 2 & 3\\\\
|
45
|
+
// \hline
|
46
|
+
// 0 & 0 & 0 & 0 & 0\\\\
|
47
|
+
// 1 & 0 & 1 & 1 & 1\\\\
|
48
|
+
// 2 & 0 & 1 & 2 & 2\\\\
|
49
|
+
// 3 & 0 & 1 & 2 & 3
|
50
|
+
// \end{array}
|
51
|
+
// &
|
52
|
+
// \begin{array}{c|cccl}
|
53
|
+
// \text{max}&0&1&2&3\\\\
|
54
|
+
// \hline
|
55
|
+
// 0 & 0 & 1 & 2 & 3\\\\
|
56
|
+
// 1 & 1 & 1 & 2 & 3\\\\
|
57
|
+
// 2 & 2 & 2 & 2 & 3\\\\
|
58
|
+
// 3 & 3 & 3 & 3 & 3
|
59
|
+
// \end{array}
|
60
|
+
// \end{array}
|
61
|
+
//
|
62
|
+
// The env_replacements function will push every line onto a stack. When an \end
|
63
|
+
// is detected, it starts popping off the stack until it reaches the corresponding
|
64
|
+
// \begin. It then modifies that line with attribute strings, an arrangement of the
|
65
|
+
// the symbols encountered while popping lines off.
|
66
|
+
extern char * env_replacements(const char *string);
|
67
|
+
|
68
|
+
// determines the column border arrangement from the array environment definition
|
69
|
+
extern const char *vertical_pipe_extract(const char *string);
|
70
|
+
|
71
|
+
// removes placeholder pipe characters from columnalign
|
72
|
+
extern const char *remove_excess_pipe_chars(const char *string);
|
73
|
+
|
74
|
+
#ifdef __cplusplus
|
75
|
+
}
|
76
|
+
#endif
|
77
|
+
|
78
|
+
#endif /* ! PARSE_EXTRAS_H */
|
@@ -0,0 +1,80 @@
|
|
1
|
+
/*
|
2
|
+
* File: stack.c
|
3
|
+
* Author: Robert I. Pitts <rip@cs.bu.edu>
|
4
|
+
* Last Modified: March 7, 2000
|
5
|
+
* Topic: Stack - Array Implementation
|
6
|
+
* ----------------------------------------------------------------
|
7
|
+
*
|
8
|
+
* This is an array implementation of a character stack.
|
9
|
+
*/
|
10
|
+
|
11
|
+
#include <stdio.h>
|
12
|
+
#include <stdlib.h>
|
13
|
+
#include "stack.h"
|
14
|
+
|
15
|
+
/************************ Function Definitions **********************/
|
16
|
+
|
17
|
+
void StackInit(stackT *stackP, int maxSize)
|
18
|
+
{
|
19
|
+
stackElementT *newContents;
|
20
|
+
|
21
|
+
/* Allocate a new array to hold the contents. */
|
22
|
+
|
23
|
+
newContents = (stackElementT *)malloc(sizeof(stackElementT) * maxSize);
|
24
|
+
|
25
|
+
if (newContents == NULL) {
|
26
|
+
fprintf(stderr, "Insufficient memory to initialize stack.\n");
|
27
|
+
exit(1); /* Exit, returning error code. */
|
28
|
+
}
|
29
|
+
|
30
|
+
stackP->contents = newContents;
|
31
|
+
stackP->maxSize = maxSize;
|
32
|
+
stackP->top = -1; /* I.e., empty */
|
33
|
+
}
|
34
|
+
|
35
|
+
void StackDestroy(stackT *stackP)
|
36
|
+
{
|
37
|
+
/* Get rid of array. */
|
38
|
+
free(stackP->contents);
|
39
|
+
|
40
|
+
stackP->contents = NULL;
|
41
|
+
stackP->maxSize = 0;
|
42
|
+
stackP->top = -1; /* I.e., empty */
|
43
|
+
}
|
44
|
+
|
45
|
+
void StackPush(stackT *stackP, stackElementT element)
|
46
|
+
{
|
47
|
+
if (StackIsFull(stackP)) {
|
48
|
+
fprintf(stderr, "Can't push element on stack: stack is full.\n");
|
49
|
+
exit(1); /* Exit, returning error code. */
|
50
|
+
}
|
51
|
+
|
52
|
+
/* Put information in array; update top. */
|
53
|
+
|
54
|
+
stackP->contents[++stackP->top] = element;
|
55
|
+
}
|
56
|
+
|
57
|
+
stackElementT StackPop(stackT *stackP)
|
58
|
+
{
|
59
|
+
if (StackIsEmpty(stackP)) {
|
60
|
+
fprintf(stderr, "Can't pop element from stack: stack is empty.\n");
|
61
|
+
exit(1); /* Exit, returning error code. */
|
62
|
+
}
|
63
|
+
|
64
|
+
return stackP->contents[stackP->top--];
|
65
|
+
}
|
66
|
+
|
67
|
+
int StackIsEmpty(stackT *stackP)
|
68
|
+
{
|
69
|
+
return stackP->top < 0;
|
70
|
+
}
|
71
|
+
|
72
|
+
int StackIsFull(stackT *stackP)
|
73
|
+
{
|
74
|
+
return stackP->top >= stackP->maxSize - 1;
|
75
|
+
}
|
76
|
+
|
77
|
+
stackElementT StackTop(stackT *stackP)
|
78
|
+
{
|
79
|
+
return stackP->contents[stackP->top];
|
80
|
+
}
|