Merge pull request #2 from catseye/develop-1.0
Develop 1.0
Chris Pressey authored 4 years ago
GitHub committed 4 years ago
0 | 0 | stringie |
1 | 1 | ======== |
2 | 2 | |
3 | This is the distribution for "stringie", an implementation of [Underload][] in ANSI C. | |
3 | This is the distribution for "stringie", an implementation of [Underload][] in | |
4 | ANSI C. | |
4 | 5 | |
5 | 6 | [Underload]: http://esolangs.org/wiki/Underload |
6 | 7 | |
7 | 8 | History |
8 | 9 | ------- |
9 | 10 | |
10 | Seeing that there was no _non_-pathological implementation of ais523's beautiful | |
11 | Underload language in C, I undertook that project one evening. (In the company of a | |
12 | bottle of really fine wine. Why, it cost almost twelve dollars.) The result is one | |
13 | of the most pedantic and boring Underload interpreters known to man. Perhaps the | |
14 | most interesting property of it is its name, "stringie", which was an accident. | |
11 | Seeing that there was no _non_-pathological implementation of ais523's | |
12 | beautiful Underload language in C, I undertook that project one evening. | |
13 | (In the company of a bottle of really fine wine. Why, it cost almost twelve | |
14 | dollars.) The result is one of the most pedantic and boring Underload | |
15 | interpreters known to man. Perhaps the most interesting property of it is its | |
16 | name, "stringie", which was an accident. | |
15 | 17 | |
16 | 18 | Building |
17 | 19 | -------- |
18 | 20 | |
19 | 21 | (cd src && make) |
20 | 22 | |
21 | You can also pass `ANSI=yes` to `make` to have the C compiler treat the source code | |
22 | as ANSI C, and this will work, because the source code is ANSI C. | |
23 | You can also pass `ANSI=yes` to `make` to have the C compiler treat the source | |
24 | code as ANSI C, and this will work, because the source code is ANSI C. | |
25 | ||
26 | It can also be build using DICE C under AmigaDOS 1.3; see the file | |
27 | [build.seq](build.seq) for details. | |
23 | 28 | |
24 | 29 | Usage |
25 | 30 | ----- |
26 | 31 | |
27 | 32 | ./bin/stringie '(Hello, world!)S' |
28 | 33 | |
29 | From this we can see that the Underload program to be interpreted is passed directly | |
30 | in the first argument. | |
34 | From this we can see that the Underload program to be interpreted is passed | |
35 | directly in the first command-line argument to the executable. | |
36 | ||
37 | However, there is also a form by which the Underload program can be read from | |
38 | a file: | |
39 | ||
40 | ./bin/stringie from eg/hello.ul | |
41 | ||
42 | Included materials | |
43 | ------------------ | |
44 | ||
45 | This distribution also contains a description of the Underload language | |
46 | in the `doc` directory, and a collection of example programs in the `eg` | |
47 | directory. These were taken from public-domain sources. | |
31 | 48 | |
32 | 49 | License |
33 | 50 | ------- |
34 | 51 | |
35 | The contents of this repository are in the public domain. See [UNLICENSE](UNLICENSE) | |
36 | for more information. | |
52 | The contents of this repository are in the public domain. See the file | |
53 | [UNLICENSE](UNLICENSE) for more information. | |
54 | ||
55 | Acknowledgements | |
56 | ---------------- | |
57 | ||
58 | Thanks to [stasoid](https://github.com/stasoid) for finding, and describing a | |
59 | fix for, [a heap-corrupting bug](https://github.com/catseye/Dipple/issues/2). |
0 | This directory is where compiled executables will be placed. |
0 | ; | |
1 | ; To build the 'stringie' executable using DICE C | |
2 | ; under AmigaDOS 1.3, you can either run | |
3 | ; | |
4 | ; protect build.seq srwd | |
5 | ; build.seq | |
6 | ; | |
7 | ; or you can simply type the following commands into the shell: | |
8 | ; | |
9 | dcc -DAUTOFLUSH src/stringie.c -o bin/stringie |
0 | Underload | |
1 | ========= | |
2 | ||
3 | (This document was converted from the public-domain | |
4 | [HTML Underload specification][] in [The Esoteric File Archive][].) | |
5 | ||
6 | Basics | |
7 | ------ | |
8 | ||
9 | Underload is a stack-based programming language that works along similar | |
10 | lines to Muriel. Although not technically speaking a functional | |
11 | language, its evaluation operator `^` (which is the only form of flow | |
12 | control) makes programming in it functional in practice. | |
13 | ||
14 | Reserved characters | |
15 | ------------------- | |
16 | ||
17 | The bracket and angle bracket characters []<> are reserved; if these are | |
18 | to appear anywhere in the program, they must be quoted by placing " | |
19 | before them. This also applies to the " character itself. Other | |
20 | characters must _not_ be quoted with " (in particular, this means that | |
21 | Underload programs cannot output strings containing unmatched | |
22 | parentheses). Parentheses are moderately reserved, in that any Underload | |
23 | program must have matched parentheses to be legal. | |
24 | ||
25 | Commands | |
26 | -------- | |
27 | ||
28 | - `~` Swap the top two elements of the stack. | |
29 | - `:` Duplicate the top element of the stack. | |
30 | - `!` Discard the top element of the stack. | |
31 | - `*` Concatenate the top element of the stack to the end of the second | |
32 | element of the stack. | |
33 | - `(` Push everything between the `(` and the matching `)` on top of | |
34 | the stack. | |
35 | - `)` Closes a `(` command. | |
36 | - `a` Encloses the top element of the stack in a pair of parentheses. | |
37 | - `^` When the `^` command is called, it includes the top element of the | |
38 | stack into the program, immediately after the `^` command, ready to be | |
39 | run next. | |
40 | - `S` Output the top element of the stack, popping it. | |
41 | ||
42 | Exceptional circumstances | |
43 | ------------------------- | |
44 | ||
45 | Pretty much anything whose behaviour isn't specifically given here (for | |
46 | instance, running `*` on an empty stack) is an error. | |
47 | ||
48 | Example programs | |
49 | ---------------- | |
50 | ||
51 | ### Hello, world! | |
52 | ||
53 | (Hello, world!)S | |
54 | ||
55 | ### Fibonacci sequence | |
56 | ||
57 | (()(*))(~:^:S*a~^a~!~*~:(/)S^):^ | |
58 | ||
59 | ### Infinite loop | |
60 | ||
61 | (:^):^ | |
62 | ||
63 | ### Quine | |
64 | ||
65 | (:aSS):aSS | |
66 | ||
67 | (The null program is also a quine. This program is more stack-based than | |
68 | functional.) | |
69 | ||
70 | [HTML Underload specification]: https://cdn.rawgit.com/graue/esofiles/7ca16941/underload/underload.html | |
71 | [The Esoteric File Archive]: https://esolangs.org/wiki/The_Esoteric_File_Archive |
0 | (:::::::):(:((^:()~((:)*~^)a~*^!!()~^))~*()~^^)~(^a(*~^)*a~*()~^!()~^)a~**^!!^S |
0 | (:(1)*(:(2)*(:(3)*(:(4)*(:(5)*(:(6)*(:(7)*(:(8)*(:(9)*(!~:^)))))))))):( | |
1 | )!(~^~(~a~*~a~*)~a*^:(0)*)~a*~:(a(:^)*())~*a(:^)*~()~(0)((!^~)())( | |
2 | )!((:(~:(,)*S~^!^)~a*^:^~!a~^*a*)~a*^:^):^ |
0 | (Hello, world!)S |
0 | (:^):^ |
0 | (12)S(*a(~:)~*^~):((1)S)~*~((2)S:*)~*:(~:()~)~*^(a(:^)*~a(*()~)~*^~^):^ |
0 | (:aS(:^S^:)Sa:):^S^:(:aS(:^S^:)Sa:) |
0 | (:aSS):aSS |
0 | (a(:^)*S):^ |
0 | (0)S((0)(1))(~:^:S*a~^~*a*~:^):^ |
28 | 28 | all: ${PROG}${EXE} |
29 | 29 | |
30 | 30 | ${PROG}${EXE}: $(OBJS) |
31 | mkdir -p ../bin/ | |
32 | 31 | $(CC) $(OBJS) -o ${PROG} $(LIBS) |
33 | 32 | |
34 | 33 | stringie${O}: stringie.c |
1 | 1 | * stringie.c -- a brain-freezingly pedantic implementation of Underload in C |
2 | 2 | * (with all the limitations that that implies) |
3 | 3 | * Chris Pressey, September 2010 |
4 | * Bug fix, August 2017: avoid memory overrun in (). Thanks to @stasoid for finding and suggesting fix. | |
4 | * August 2017: bug fix to avoid memory overrun in (). Thanks to @stasoid for finding and suggesting fix. | |
5 | * Summer 2018: own implementation of strdup to avoid warnings; ability to read from file; AUTOFLUSH; 1.0. | |
5 | 6 | * This work is in the public domain. |
6 | 7 | */ |
7 | 8 | |
15 | 16 | } *root; |
16 | 17 | |
17 | 18 | void run(char *); |
19 | ||
20 | char *strdupe(const char *s) | |
21 | { | |
22 | char *t = malloc(strlen(s) + 1); | |
23 | strcpy(t, s); | |
24 | return t; | |
25 | } | |
18 | 26 | |
19 | 27 | char *pop(void) |
20 | 28 | { |
40 | 48 | { |
41 | 49 | char *e, *f; |
42 | 50 | e = pop(); |
43 | f = strdup(e); | |
51 | f = strdupe(e); | |
44 | 52 | push(e); |
45 | 53 | push(f); |
46 | 54 | } |
89 | 97 | char *e; |
90 | 98 | e = pop(); |
91 | 99 | printf("%s", e); |
100 | #ifdef AUTOFLUSH | |
101 | fflush(stdout); | |
102 | #endif | |
92 | 103 | free(e); |
93 | 104 | } |
94 | 105 | |
164 | 175 | free(program); |
165 | 176 | } |
166 | 177 | |
178 | char *readfile(FILE *f) | |
179 | { | |
180 | char chunk[256]; | |
181 | char *buffer; | |
182 | int size = 256; | |
183 | int len = 0; | |
184 | int n; | |
185 | ||
186 | buffer = malloc(size); | |
187 | ||
188 | n = fread(chunk, 1, 256, f); | |
189 | while (n > 0) { | |
190 | if (len + n > size) { | |
191 | size *= 2; | |
192 | buffer = realloc(buffer, size); | |
193 | } | |
194 | memcpy(buffer + len, chunk, n); | |
195 | len += n; | |
196 | n = fread(chunk, 256, 1, f); | |
197 | } | |
198 | ||
199 | /* NUL-terminate the buffer; but first, make sure the NUL can fit! */ | |
200 | if (len + 1 > size) { | |
201 | size *= 2; | |
202 | buffer = realloc(buffer, size); | |
203 | } | |
204 | buffer[len + 1] = '\0'; | |
205 | ||
206 | return buffer; | |
207 | } | |
208 | ||
167 | 209 | int main(int argc, char **argv) |
168 | 210 | { |
169 | char *program = strdup(argv[1]); | |
211 | char *program; | |
212 | FILE *f; | |
213 | ||
214 | if (argc >= 1) { | |
215 | if (!strcmp(argv[1], "from") && argc >= 2) { | |
216 | if ((f = fopen(argv[2], "r")) == NULL) { | |
217 | exit(1); | |
218 | } | |
219 | program = readfile(f); | |
220 | fclose(f); | |
221 | } else { | |
222 | program = strdupe(argv[1]); | |
223 | } | |
224 | } | |
170 | 225 | root = NULL; |
171 | 226 | run(program); |
172 | 227 | exit(0); |