git @ Cat's Eye Technologies Befunge-93 / 1167fd1
Merge pull request #8 from catseye/historic-materials Add historic materials recovered from Amiga disk backup images. Chris Pressey authored 3 years ago GitHub committed 3 years ago
30 changed file(s) with 1785 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 Historical Befunge-93 Sources
1 =============================
2
3 Found amongst my Amiga disk backup images.
4
5 [bef-1.0rc2](bef-1.0rc2)
6 ------------------------
7
8 Sources for what was probably not the first release of the Befunge
9 distribution (its language document, reference implementation, and
10 the initial example programs), but something very close to it.
11
12 Both the C source code for the interpreter, and the language document,
13 describes this as "version 1.0". However, this version does not yet
14 mention or support the backquote (greater-than) command, and
15 subsequent release history (in the comment at the top of `bef.c`)
16 suggests that it was present in 1.0 and not added in a later version.
17
18 The language document is clearly the document on which the current
19 `Befunge-93.markdown` is based, but it includes an introductory HISTORY
20 section that was at some point subsequently removed.
21
22 The confusingly-named `src` directory contains example programs, along
23 with a `sources.doc` which describes and attributes each of them.
24
25 However, the last 3 examples listed in `sources.doc`, namely
26 `anagram.bf`, `numer.bf`, and `toupper.bf`, were not actually present
27 in the backup image. But they did appear in later releases, and are
28 included in the `eg` directory of the reference distribution as of this
29 writing.
30
31 In addition, the `chars.bf` example differs from the one in the
32 reference distribution as of this writing, suggesting it was edited at
33 some point, but by who and for what purpose is not clear.
34
35 [bef-1.0rc1](bef-1.0rc1)
36 ------------------
37
38 Sources, document, and example programs dated September 5, 1993.
39
40 The language document is the same as in bef-1.0, and so claims that
41 this is version 1.0. The source code for the interpreter, however,
42 makes no claims as to its version (and in fact is pretty stingy on
43 comments across the board.)
44
45 In fact this C source may well have been the first thrown-together
46 version of the Befunge interpreter.
47
48 There are two example programs here which did not appear in 1.0:
49 `beep.bf`, which simply outputs a BEL character, and `huh.bf`, which
50 outputs a random (but not uniformly random) sequence of 6's and 7's.
51
52 [prehistoric](prehistoric)
53 --------------------------
54
55 As described in its contained README, this subdirectory contains documents
56 describing an entirely different language, also called "Befunge", dated
57 January 1993, illustrating how long the name "Befunge" existed before the
58 programming language now known as Befunge.
0 #include <stdio.h>
1 #include <string.h>
2 #include <stdlib.h>
3 #include <ctype.h>
4 #include <time.h>
5 #include <catseye.h>
6
7 #define cur pg[y].l[x]
8
9 struct stack /* stack structure, for values on stack */
10 {
11 signed long val;
12 struct stack *next;
13 } *head; /* head of stack */
14
15 struct line
16 {
17 char l[80];
18 };
19
20 struct line pg[25];
21
22 int x=0, y=0;
23 int dx=1, dy=0;
24 int stringmode = 0;
25
26 void push(signed long val);
27 signed long pop();
28
29 main(argc, argv)
30 int argc;
31 char **argv;
32 {
33 FILE *f;
34 srand(time(0));
35
36 if (argc<2)
37 {
38 printf("USAGE : %s <befunge-source>\n", argv[0]);
39 exit(0);
40 }
41 if (f=fopen(argv[1], "r"))
42 {
43 int i=0;
44 while(!feof(f))
45 {
46 fgets(pg[i].l, 79, f);
47 shrink(pg[i].l);
48 while(strlen(pg[i].l)<79)
49 strcat(pg[i].l, " ");
50 i++;
51 if (i>24)
52 break;
53 }
54 fclose(f);
55 } else
56 {
57 printf("Error : couldn't open '%s' for input.\n", argv[1]);
58 exit(0);
59 }
60
61 while(cur!='@')
62 {
63 if(stringmode&&(cur!='"'))
64 push(cur); else
65 if(isdigit(cur))
66 push(cur-'0'); else
67 switch(cur)
68 {
69 case '>' : dx = 1; dy = 0; break;
70 case '<' : dx = -1; dy = 0; break;
71 case '^' : dx = 0; dy = -1; break;
72 case 'v' : dx = 0; dy = 1; break;
73 case '|' : dx = 0; if(pop()) dy = -1; else dy = 1; break;
74 case '_' : dy = 0; if(pop()) dx = -1; else dx = 1; break;
75 case '+' : push(pop()+pop()); break;
76 case '-' : push(-1*(pop()-pop())); break;
77 case '*' : push(pop()*pop()); break;
78 case '/' : { int a = pop(); int b = pop(); push(b / a); } break;
79 case '%' : { int a = pop(); int b = pop(); push(b % a); } break;
80 case '\\' : { int a = pop(); int b = pop(); push(a); push(b); } break;
81 case '.' : printf("%ld ", pop()); fflush(stdout); break;
82 case ',' : printf("%c", pop()); fflush(stdout); break;
83 case '"' : stringmode = !stringmode; break;
84 case ':' : { int a = pop(); push(a); push(a); } break;
85 case '!' : push(!pop()); break;
86 case '#' : x += dx; y += dy; break;
87 case '$' : pop(); break;
88 case '?' : switch((rand()/32)%4)
89 {
90 case 0 : dx = 1; dy = 0; break;
91 case 1 : dx = -1; dy = 0; break;
92 case 2 : dx = 0; dy = -1; break;
93 case 3 : dx = 0; dy = 1; break;
94 } break;
95 case '&' : { signed long b; fscanf(stdin, "%ld", &b); push(b); } break;
96 case '~' : { char c=fgetc(stdin); push(c); } break;
97 case 'g' : { int y=pop(), x=pop(); push(cur); } break;
98 case 'p' : { int y=pop(), x=pop(); cur=pop(); } break;
99 default : break;
100 }
101 x += dx;
102 y += dy;
103 }
104 exit(0);
105 }
106
107 /*
108 * pushes a value onto the stack.
109 */
110 void push(signed long val)
111 {
112 struct stack *s;
113 s = (struct stack *) malloc(sizeof(struct stack));
114 s->val = val;
115 s->next = head;
116 head = s;
117 }
118
119 /*
120 * pops a value off the stack. returns 0 in case of underflow.
121 */
122 signed long pop()
123 {
124 signed long v;
125 struct stack *s = head;
126 if (s)
127 {
128 v = head->val;
129 head = head->next;
130 free(s);
131 return v;
132 } else
133 {
134 return 0;
135 }
136 }
0 B E F U N G E
1 -------------
2 (v1.0)
3
4 Deranged Interpreter
5 in the style of 'bf' and 'False'
6
7 Chris Pressey
8 September, 1993
9
10 I. HISTORY
11
12 The creation of the word 'Befunge' I owe to Curtis Coleman, who, at
13 4am, in chat with me on my BBS, spontaneously typed it. I, of course,
14 recognized the linguistic significance of the word and introduced it
15 into my slang vocabulary. Over the past year or so it has been a verb,
16 usually used in past tense ('befunged'), which has a vague meaning,
17 generally referring to something which is (a) oddball, (b) broken,
18 (c) logically and by all accounts SHOULD be broken, but still works, or
19 (d) a just plain silly way of doing something, not to be a better way,
20 but just to be different.
21
22 The creation of a language called 'Befunge' followed soon after - in
23 theory only, of course, until now. At first, it was a Forth derivative
24 which, I believe, was supposed to not care if you were mixing strings
25 with integers and then dividing by reals, or whatever. Next, it sort of
26 became an object-oriented assembly language which promoted self-modifying
27 code. Then, I sort of lost interest in languages for a while.
28
29 However, recently, I was having a discussion with Shawn Vincent, a friend
30 of mine, about compilers and interpreters. Actually, 'discussions' between
31 Shawn and I are usually better referred to as 'debates' or, even more
32 appropriately, 'arguments.' Anyway, he declared that it was always easier
33 to write a compiler than an interpreter. I disagreed, saying that there
34 are some languages out there where and interpreter is easier to write than
35 a compiler. Anyway, motivated by this 'discussion,' I pulled out the source
36 to an old RPN (Reverse Polish Notation) calculator I was working on, added
37 an if loop, and a while loop, and function handling, and hey presto - a
38 working interpreter. I called it Maentwrog, the Celtic word for a computer
39 spelling mistake (see _The Meaning of Liff_, Douglas Adams, John Lloyd.)
40
41 But then, a few days ago, I started thinking odd thoughts. I was, and
42 still am, fascinated by 'minimalist' languages like 'bf' ('brainf*ck'),
43 by Urban Mueller, and 'False', by Wouter van Oortmerssen (both available
44 through AmiNet, btw.) I was also thinking about flowcharts, and how,
45 if one made a BASIC interpreter, it wouldn't be so hard to, instead of
46 having a GOTO xxxx statement, just have a series of ASCII characters, like
47 --- and |, leading to the statement you wanted to go to... and the idea
48 for Befunge was born.
49
50 I went home that evening, ripped off the stack functions from Maentwrog,
51 and wrote Befunge.
52
53 II. THE BASICS
54
55 Most likely the most unique element of Befunge programming is the
56 Program Counter (PC.) In most, indeed, almost all, languages, the
57 program counter is continually moving forward through the program,
58 occassionally jumping to another spot in the code (but continuing forward
59 nonetheless.)
60
61 The PC in Befunge, however, is subject to no such restrictions. It
62 may go forward, or backward, or even LEFT OR RIGHT. A Befunge program
63 is treated as an 80x25 page of ASCII text. Certain commands change
64 the direction of the PC. By default, the PC points to the upper-left
65 corner of the program, and is oriented to go left-to-right.
66
67 Each command in Befunge is one character (so your programs have a current
68 maximum size of 80x25 commands; this may change in the future.) There
69 are no variables as such, but they may be simulated, and there is an RPN
70 stack. Befunge programs allow for self-modification; and due to their
71 2-dimensional nature, they allow for some very STRANGE things to happen.
72
73 III. THE USAGE
74
75 From the Shell or CLI, the usage is :
76
77 bef <befunge-source>
78
79 Befunge, obviously enough, does not run from the workbench. <befunge-
80 source> is required. There is no immediate mode for befunge (for obvious
81 reasons.)
82
83 IV. THE STACK
84
85 Befunge supports an RPN, Forth-like stack of signed long integers. There
86 are a few ways to add values to the stack. A digit, such as '7', will
87 be pushed on the stack. (How to make values greater than 9 be put on the
88 stack is explained below.) A double quote, '"', starts 'string-mode',
89 and all subsequent characters will have their ASCII value pushed onto the
90 stack until another '"' is located. <input>
91
92 There are a few basic mathematical commands, like Forth :
93
94 + addition
95 - subtraction
96 / integer division
97 * multiplication
98 % modulo
99 ! logical negation
100
101 These are explained in greated detail in the 'Commands' section.
102
103 In order to push a number greater than 9 on the stack, one must do math
104 with numbers less than or equal to 9. This is a pain, but it makes you
105 think :-) For example, to push '123' onto the stack, one might push
106 9, then 9, then multiply (leaving 81), then push 7, then 6, then multiply
107 (leaving 81 and 42,) then add (leaving 123.) In Befunge, this would
108 look something like :
109
110 99*76*+
111
112 This is, of course, presuming the PC starts at the first '9' and is working
113 towards the right.
114
115 NB. If the stack should be empty when you want to pop something off,
116 be warned that this will not generate an underflow! It will simply
117 return '0' to you. Hope you can live with it! :-)
118
119 V. MORE ON THE PC
120
121 There are 5 commands which directly control the PC direction: '>', '<',
122 'v', '^', and '?'. '>' makes the PC travel to the right; '<' to the left;
123 'v' down; '^' up; and '?' in a random direction. So, the following
124 example is an infinite loop :
125
126 ><
127
128 As is :
129
130 >v
131 ^<
132
133 As is :
134
135 >v>v
136 >^v
137 ^ <
138
139 (Note that the program always starts in the upper left hand corner, moving
140 towards the right. Also note that ' ' (space) is a null command which
141 does nothing.)
142
143 VI. LOGIC : THE IF STATEMENT
144
145 The 'if' statement in Befunge is either '_' or '|', depending on how you
146 want to branch. Both pop a value off the stack and check to see if it
147 is true (non-zero,) and change the direction of the PC accordingly.
148 '_' acts like '<' if it is true, and '>' if it is false.
149 '|' acts like '^' if it is true, and 'v' if it is false.
150
151 'While' loops can be made by sticking an 'if' in an infinite loop.
152 For example,
153
154 >_@
155
156 (This strange little program will pop all of the non-zero values off the
157 stack, and the first zero value, then exit ['@' is the exit command.]
158 Don't worry... clearer examples are in the source :-)
159
160 VII. OUTPUT
161
162 Simply enough : '.' will pop a value off the stack and output it as
163 an integer, followed by a space. (somewhat like Forth.) ',' will pop a
164 value and output as ASCII with no space.
165
166 eg.
167
168 665+*1-, will print out ASCII 65 ("A".)
169 665+*1-, will print out "65 ".
170
171
172 VIII. SPECIAL COMMANDS (BRIEF)
173
174 '#' is the 'bridge' command... it causes the next command which would
175 normally be executed to be skipped over, and not executed. For example,
176
177 >123...@
178
179 would output "3 2 1 " but
180
181 >123#...@
182
183 would output "3 2 " with one of the '.''s being skipped. Judicious use
184 of '#' can make for some very interesting code!
185
186 ':' is the duplicating command. It simply makes a copy of the top element
187 of the stack. This is useful. Remember that '>_@' example? This is
188 probably the most useful form of it :
189
190 v.<
191 >:|
192 @
193
194 Since this makes duplicates, each number is checked, and if non-zero,
195 printed.
196
197 '$' pops a number off the stack, but does nothing with it. So,
198
199 123.$.@
200
201 results in "3 1 ".
202
203 '\' swaps the top two elements of the stack. So,
204
205 123\...@
206
207 results in "2 3 1 ".
208
209
210
211 APPENDIX A. COMMAND SUMMARY.
212
213 COMMAND INITIAL STACK RESULT (STACK)
214 ------- ------------- -----------------
215
216 + (add) <value1> <value2> <value1 + value2>
217 - (subtract) <value1> <value2> <value1 - value2>
218 * (multiply) <value1> <value2> <value1 * value2>
219 / (divide) <value1> <value2> <value1 / value2> (nb. integer)
220 % (modulo) <value1> <value2> <value1 mod value2>
221 ! (not) <value> <0 if value non-zero, 1 otherwise>
222
223 > (right) PC -> right
224 < (left) PC -> left
225 ^ (up) PC -> up
226 v (down) PC -> down
227
228 ? (random) PC -> right? left? up? down? ???
229
230 _ (horizontal if) <boolean value> PC->left if <value>, else PC->right
231 | (vertical if) <boolean value> PC->up if <value>, else PC->down
232
233 " (stringmode) Toggles 'stringmode'
234
235 : (dup) <value> <value> <value>
236 \ (swap) <value1> <value2> <value2> <value1>
237 $ (pop) <value> pops <value> but does nothing
238 . (pop) <value> outputs <value> as integer
239 , (pop) <value> outputs <value> as ASCII
240
241 # (bridge) 'jumps' PC one farther; skips
242 over next command
243
244 g (get) <x> <y> <value at (x,y)>
245 p (put) <value> <x> <y> puts <value> at (x,y)
246
247 & (input value) <value user entered>
248 ~ (input character) <character user entered>
249
250 @ (end) ends program
251
0
1 /*
2 * catseye.h
3 *
4 * not Copyright 1993, Chris Pressey
5 */
6
7 #ifndef CATSEYE_H
8 #define CATSEYE_H
9
10 #define shrink(s) s[strlen(s)-1]=0
11 #define space2us(s) {int i=0;while(s[i++]) if(s[i]==' ') s[i]='_';}
12 #define colon2dash(s) {int i=0;while(s[i++]) if(s[i]==':') s[i]='-';}
13
14 #endif
15
0 25*3*4+>:."=",:,25*,1+:88*2*-#v_@
1 ^ <
0 #v #< v
1 >v"Hello... I'm Dr. X. How do you feel today? "0<
2 ,: #
3 ^_$v <
4 >~25*-| > v
5 > 0#v?v
6 ^"Do your friends find this reasonable? "<
7 ^"How long have you felt this way? " <
8 ^"How do you feel about that? " <
9 ^"Are you disturbed by this? " <
0 v
1 >v"Please enter a number (1-16) : "0<
2 ,: >$*99g1-:99p#v_.25*,@
3 ^_&:1-99p>:1-:!|10 <
4 ^ <
5
0 v
1 >v"Hello world!"0<
2 ,:
3 ^_25*,@
0 v< <
1 . 7
2 >6.?<
3 ^ <
0 v <
1 >0#v # "Hello, World!" # v#0 <
2 >v # >v
3 ,: ,:
4 ^_25*,^ ^_25*,^
0 v <
1 >?"/",^
2 >"\",^
0 vv < <
1 2
2 ^ v<
3 v1<?>3v4
4 ^ ^
5 > >?> ?>5^
6 v v
7 v9<?>7v6
8 v v<
9 8
10 . > > ^
11 ^<
0 vv_v#:"*********"*25< 01 = x coord
1 8,: > ^ 02 = y coord
2 0>^ ^"* * *"*25<
3 1 > ^
4 p ^"* *** * *"*25<
5 2 > ^
6 0 ^"* * *"*25<
7 2 > ^
8 p ^"* * * *"*25<
9 " > ^
10 O ^"* ***** *"*25< >,v
11 " > ^ |:<"You hit a wall! Game over!"0<
12 0 ^"* * *"*25< >25*,@ |-*84gg20g10<
13 1 > ^v ,*62 pg20g10"O"< <
14 g ^"* * *"*25< >00g"w"-|
15 0 > ^ >00g"e"-| >01g1-01p^
16 2 ^"*********"*250< >00g"s"-| >01g1+01p ^
17 g > " "01g02gp "?",~~$:00p"n"-| >02g2+02p ^
18 >p 62*, ^ >02g2-02p ^
0 /*
1
2 bef.c
3 Befunge Interpreter - v1.0, Sept 1993, Chris Pressey
4
5 usage :
6
7 bef <befunge-source>
8
9 compilation :
10
11 Amiga : dcc bef.c -o bef
12 Unix : acc bef.c -o bef
13
14 */
15
16 /********************************************************* #INCLUDE'S */
17
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <ctype.h>
22 #include <time.h>
23 #include <catseye.h>
24
25 /********************************************************** #DEFINE'S */
26
27 #define LINEWIDTH 80 /* 0 .. 79 */
28 #define PAGEHEIGHT 25 /* 0 .. 24 */
29
30 #define cur pg[y * LINEWIDTH + x]
31
32 /********************************************************* STRUCTURES */
33
34 struct stack /* stack structure, for values on stack */
35 {
36 signed long val;
37 struct stack *next;
38 }
39 *head; /* head of stack */
40
41 /*************************************************** GLOBAL VARIABLES */
42
43 char pg[LINEWIDTH * PAGEHEIGHT]; /* befunge 'page' of source */
44 int x = 0, y = 0; /* x and y of the PC */
45 int dx = 1, dy = 0; /* direction of the PC */
46 int stringmode = 0; /* flag : are we in string mode? */
47
48 /********************************************************* PROTOTYPES */
49
50 void push (signed long val);
51 signed long pop ();
52
53 /******************************************************* MAIN PROGRAM */
54
55 main (argc, argv)
56 int argc;
57 char **argv;
58 {
59 FILE *f;
60 srand (time (0));
61
62 if (argc < 2)
63 {
64 printf ("USAGE : %s <befunge-source>\n", argv[0]);
65 exit (0);
66 }
67 if (f = fopen (argv[1], "r")) /*** Input Phase */
68 {
69 int x = 0, y = 0;
70 while (!feof (f))
71 {
72 cur = fgetc (f);
73 if (cur == '\n')
74 {
75 cur = ' ';
76 x = 0;
77 y++;
78 if (y >= PAGEHEIGHT)
79 break;
80 }
81 else
82 {
83 x++;
84 if (x >= LINEWIDTH)
85 {
86 x = 0;
87 y++;
88 if (y >= PAGEHEIGHT)
89 break;
90 }
91 }
92 }
93 fclose (f);
94 }
95 else
96 {
97 printf ("Error : couldn't open '%s' for input.\n", argv[1]);
98 exit (0);
99 }
100
101 while (cur != '@') /*** Intepreting Phase */
102 {
103 if (stringmode && (cur != '"'))
104 push (cur);
105 else if (isdigit (cur))
106 push (cur - '0');
107 else
108 switch (cur)
109 {
110 case '>': /* PC Right */
111 dx = 1;
112 dy = 0;
113 break;
114 case '<': /* PC Left */
115 dx = -1;
116 dy = 0;
117 break;
118 case '^': /* PC Up */
119 dx = 0;
120 dy = -1;
121 break;
122 case 'v': /* PC Down */
123 dx = 0;
124 dy = 1;
125 break;
126 case '|': /* Vertical 'If' */
127 dx = 0;
128 if (pop ())
129 dy = -1;
130 else
131 dy = 1;
132 break;
133 case '_': /* Horizontal 'If' */
134 dy = 0;
135 if (pop ())
136 dx = -1;
137 else
138 dx = 1;
139 break;
140 case '+': /* Add */
141 push (pop () + pop ());
142 break;
143 case '-': /* Subtract */
144 push (-1 * (pop () - pop ()));
145 break;
146 case '*': /* Multiply */
147 push (pop () * pop ());
148 break;
149 case '/': /* Integer Divide */
150 {
151 int a = pop ();
152 int b = pop ();
153 push (b / a);
154 }
155 break;
156 case '%': /* Modulo */
157 {
158 int a = pop ();
159 int b = pop ();
160 push (b % a);
161 }
162 break;
163 case '\\': /* Swap */
164 {
165 int a = pop ();
166 int b = pop ();
167 push (a);
168 push (b);
169 }
170 break;
171 case '.': /* Pop Out Integer */
172 printf ("%ld ", pop ());
173 fflush (stdout);
174 break;
175 case ',': /* Pop Out ASCII */
176 printf ("%c", pop ());
177 fflush (stdout);
178 break;
179 case '"': /* Toggle String Mode */
180 stringmode = !stringmode;
181 break;
182 case ':': /* Duplicate */
183 {
184 int a = pop ();
185 push (a);
186 push (a);
187 }
188 break;
189 case '!': /* Negate */
190 push (!pop ());
191 break;
192 case '#': /* Bridge */
193 x += dx;
194 y += dy;
195 break;
196 case '$': /* Pop and Discard */
197 pop ();
198 break;
199 case '?': /* Random Redirect */
200 switch ((rand () / 32) % 4)
201 {
202 case 0:
203 dx = 1;
204 dy = 0;
205 break;
206 case 1:
207 dx = -1;
208 dy = 0;
209 break;
210 case 2:
211 dx = 0;
212 dy = -1;
213 break;
214 case 3:
215 dx = 0;
216 dy = 1;
217 break;
218 }
219 break;
220 case '&': /* Input Integer */
221 {
222 signed long b;
223 fscanf (stdin, "%ld", &b);
224 push (b);
225 }
226 break;
227 case '~': /* Input ASCII */
228 {
229 char c = fgetc (stdin);
230 push (c);
231 }
232 break;
233 case 'g': /* Get Value */
234 {
235 int y = pop (), x = pop ();
236 push (cur);
237 }
238 break;
239 case 'p': /* Put Value */
240 {
241 int y = pop (), x = pop ();
242 cur = pop ();
243 }
244 break;
245 default:
246 break;
247 }
248 x += dx;
249 y += dy;
250 }
251 exit (0);
252 }
253
254 /*
255 * pushes a value onto the stack.
256 */
257 void
258 push (signed long val)
259 {
260 struct stack *s;
261 s = (struct stack *) malloc (sizeof (struct stack));
262 s->val = val;
263 s->next = head;
264 head = s;
265 }
266
267 /*
268 * pops a value off the stack. returns 0 in case of underflow.
269 */
270 signed long
271 pop ()
272 {
273 signed long v;
274 struct stack *s = head;
275 if (s)
276 {
277 v = head->val;
278 head = head->next;
279 free (s);
280 return v;
281 }
282 else
283 {
284 return 0;
285 }
286 }
0 B E F U N G E
1 -------------
2 (v1.0)
3
4 Deranged Interpreter
5 in the style of 'bf' and 'False'
6
7 Chris Pressey
8 September, 1993
9
10 I. HISTORY
11
12 The creation of the word 'Befunge' I owe to Curtis Coleman, who, at
13 4am, in chat with me on my BBS, spontaneously typed it. I, of course,
14 recognized the linguistic significance of the word and introduced it
15 into my slang vocabulary. Over the past year or so it has been a verb,
16 usually used in past tense ('befunged'), which has a vague meaning,
17 generally referring to something which is (a) oddball, (b) broken,
18 (c) logically and by all accounts SHOULD be broken, but still works, or
19 (d) a just plain silly way of doing something, not to be a better way,
20 but just to be different.
21
22 The creation of a language called 'Befunge' followed soon after - in
23 theory only, of course, until now. At first, it was a Forth derivative
24 which, I believe, was supposed to not care if you were mixing strings
25 with integers and then dividing by reals, or whatever. Next, it sort of
26 became an object-oriented assembly language which promoted self-modifying
27 code. Then, I sort of lost interest in languages for a while.
28
29 However, recently, I was having a discussion with Shawn Vincent, a friend
30 of mine, about compilers and interpreters. Actually, 'discussions' between
31 Shawn and I are usually better referred to as 'debates' or, even more
32 appropriately, 'arguments.' Anyway, he declared that it was always easier
33 to write a compiler than an interpreter. I disagreed, saying that there
34 are some languages out there where and interpreter is easier to write than
35 a compiler. Anyway, motivated by this 'discussion,' I pulled out the source
36 to an old RPN (Reverse Polish Notation) calculator I was working on, added
37 an if loop, and a while loop, and function handling, and hey presto - a
38 working interpreter. I called it Maentwrog, the Celtic word for a computer
39 spelling mistake (see _The Meaning of Liff_, Douglas Adams, John Lloyd.)
40
41 But then, a few days ago, I started thinking odd thoughts. I was, and
42 still am, fascinated by 'minimalist' languages like 'bf' ('brainf*ck'),
43 by Urban Mueller, and 'False', by Wouter van Oortmerssen (both available
44 through AmiNet, btw.) I was also thinking about flowcharts, and how,
45 if one made a BASIC interpreter, it wouldn't be so hard to, instead of
46 having a GOTO xxxx statement, just have a series of ASCII characters, like
47 --- and |, leading to the statement you wanted to go to... and the idea
48 for Befunge was born.
49
50 I went home that evening, ripped off the stack functions from Maentwrog,
51 and wrote Befunge.
52
53 II. THE BASICS
54
55 Most likely the most unique element of Befunge programming is the
56 Program Counter (PC.) In most, indeed, almost all, languages, the
57 program counter is continually moving forward through the program,
58 occassionally jumping to another spot in the code (but continuing forward
59 nonetheless.)
60
61 The PC in Befunge, however, is subject to no such restrictions. It
62 may go forward, or backward, or even LEFT OR RIGHT. A Befunge program
63 is treated as an 80x25 page of ASCII text. Certain commands change
64 the direction of the PC. By default, the PC points to the upper-left
65 corner of the program, and is oriented to go left-to-right.
66
67 Each command in Befunge is one character (so your programs have a current
68 maximum size of 80x25 commands; this may change in the future.) There
69 are no variables as such, but they may be simulated, and there is an RPN
70 stack. Befunge programs allow for self-modification; and due to their
71 2-dimensional nature, they allow for some very STRANGE things to happen.
72
73 III. THE USAGE
74
75 From the Shell or CLI, the usage is :
76
77 bef <befunge-source>
78
79 Befunge, obviously enough, does not run from the workbench. <befunge-
80 source> is required. There is no immediate mode for befunge (for obvious
81 reasons.)
82
83 IV. THE STACK
84
85 Befunge supports an RPN, Forth-like stack of signed long integers. There
86 are a few ways to add values to the stack. A digit, such as '7', will
87 be pushed on the stack. (How to make values greater than 9 be put on the
88 stack is explained below.) A double quote, '"', starts 'string-mode',
89 and all subsequent characters will have their ASCII value pushed onto the
90 stack until another '"' is located. <input>
91
92 There are a few basic mathematical commands, like Forth :
93
94 + addition
95 - subtraction
96 / integer division
97 * multiplication
98 % modulo
99 ! logical negation
100
101 These are explained in greated detail in the 'Commands' section.
102
103 In order to push a number greater than 9 on the stack, one must do math
104 with numbers less than or equal to 9. This is a pain, but it makes you
105 think :-) For example, to push '123' onto the stack, one might push
106 9, then 9, then multiply (leaving 81), then push 7, then 6, then multiply
107 (leaving 81 and 42,) then add (leaving 123.) In Befunge, this would
108 look something like :
109
110 99*76*+
111
112 This is, of course, presuming the PC starts at the first '9' and is working
113 towards the right.
114
115 NB. If the stack should be empty when you want to pop something off,
116 be warned that this will not generate an underflow! It will simply
117 return '0' to you. Hope you can live with it! :-)
118
119 V. MORE ON THE PC
120
121 There are 5 commands which directly control the PC direction: '>', '<',
122 'v', '^', and '?'. '>' makes the PC travel to the right; '<' to the left;
123 'v' down; '^' up; and '?' in a random direction. So, the following
124 example is an infinite loop :
125
126 ><
127
128 As is :
129
130 >v
131 ^<
132
133 As is :
134
135 >v>v
136 >^v
137 ^ <
138
139 (Note that the program always starts in the upper left hand corner, moving
140 towards the right. Also note that ' ' (space) is a null command which
141 does nothing.)
142
143 VI. LOGIC : THE IF STATEMENT
144
145 The 'if' statement in Befunge is either '_' or '|', depending on how you
146 want to branch. Both pop a value off the stack and check to see if it
147 is true (non-zero,) and change the direction of the PC accordingly.
148 '_' acts like '<' if it is true, and '>' if it is false.
149 '|' acts like '^' if it is true, and 'v' if it is false.
150
151 'While' loops can be made by sticking an 'if' in an infinite loop.
152 For example,
153
154 >_@
155
156 (This strange little program will pop all of the non-zero values off the
157 stack, and the first zero value, then exit ['@' is the exit command.]
158 Don't worry... clearer examples are in the source :-)
159
160 VII. OUTPUT
161
162 Simply enough : '.' will pop a value off the stack and output it as
163 an integer, followed by a space. (somewhat like Forth.) ',' will pop a
164 value and output as ASCII with no space.
165
166 eg.
167
168 665+*1-, will print out ASCII 65 ("A".)
169 665+*1-, will print out "65 ".
170
171
172 VIII. SPECIAL COMMANDS (BRIEF)
173
174 '#' is the 'bridge' command... it causes the next command which would
175 normally be executed to be skipped over, and not executed. For example,
176
177 >123...@
178
179 would output "3 2 1 " but
180
181 >123#...@
182
183 would output "3 2 " with one of the '.''s being skipped. Judicious use
184 of '#' can make for some very interesting code!
185
186 ':' is the duplicating command. It simply makes a copy of the top element
187 of the stack. This is useful. Remember that '>_@' example? This is
188 probably the most useful form of it :
189
190 v.<
191 >:|
192 @
193
194 Since this makes duplicates, each number is checked, and if non-zero,
195 printed.
196
197 '$' pops a number off the stack, but does nothing with it. So,
198
199 123.$.@
200
201 results in "3 1 ".
202
203 '\' swaps the top two elements of the stack. So,
204
205 123\...@
206
207 results in "2 3 1 ".
208
209
210
211 APPENDIX A. COMMAND SUMMARY.
212
213 COMMAND INITIAL STACK RESULT (STACK)
214 ------- ------------- -----------------
215
216 + (add) <value1> <value2> <value1 + value2>
217 - (subtract) <value1> <value2> <value1 - value2>
218 * (multiply) <value1> <value2> <value1 * value2>
219 / (divide) <value1> <value2> <value1 / value2> (nb. integer)
220 % (modulo) <value1> <value2> <value1 mod value2>
221 ! (not) <value> <0 if value non-zero, 1 otherwise>
222
223 > (right) PC -> right
224 < (left) PC -> left
225 ^ (up) PC -> up
226 v (down) PC -> down
227
228 ? (random) PC -> right? left? up? down? ???
229
230 _ (horizontal if) <boolean value> PC->left if <value>, else PC->right
231 | (vertical if) <boolean value> PC->up if <value>, else PC->down
232
233 " (stringmode) Toggles 'stringmode'
234
235 : (dup) <value> <value> <value>
236 \ (swap) <value1> <value2> <value2> <value1>
237 $ (pop) <value> pops <value> but does nothing
238 . (pop) <value> outputs <value> as integer
239 , (pop) <value> outputs <value> as ASCII
240
241 # (bridge) 'jumps' PC one farther; skips
242 over next command
243
244 g (get) <x> <y> <value at (x,y)>
245 p (put) <value> <x> <y> puts <value> at (x,y)
246
247 & (input value) <value user entered>
248 ~ (input character) <character user entered>
249
250 @ (end) ends program
251
0
1 /*
2 * catseye.h
3 *
4 * not Copyright 1993, Chris Pressey
5 */
6
7 #ifndef CATSEYE_H
8 #define CATSEYE_H
9
10 #define shrink(s) s[strlen(s)-1]=0
11 #define space2us(s) {int i=0;while(s[i++]) if(s[i]==' ') s[i]='_';}
12 #define colon2dash(s) {int i=0;while(s[i++]) if(s[i]==':') s[i]='-';}
13
14 #endif
15
0 25*3*4+>:."=",:,25*,1+:88*2*-#v_@
1 ^ <
0 #v #< v
1 >v"Hello... I'm Dr. X. How do you feel today? "0<
2 ,: #
3 ^_$v <
4 >~25*-| > v
5 > 0#v?v
6 ^"Do your friends find this reasonable? "<
7 ^"How long have you felt this way? " <
8 ^"How do you feel about that? " <
9 ^"Are you disturbed by this? " <
0 v
1 >v"Please enter a number (1-16) : "0<
2 ,: >$*99g1-:99p#v_.25*,@
3 ^_&:1-99p>:1-:!|10 <
4 ^ <
5
0 v
1 >v"Hello world!"0<
2 ,:
3 ^_25*,@
0 v <
1 >0#v # "Hello, World!" # v#0 <
2 >v # >v
3 ,: ,:
4 ^_25*,^ ^_25*,^
0 v <
1 >?"/",^
2 >"\",^
0 222p882**1+11p>133p >33g1+33p 22g33g- v>22g33g%#v_v
1 o >|
2 2 v,,,,, ,,,,,.g22"is prime."<
3 1 > v^ <
4 ^_@#-g11g22p22+1g22,*25<,,,,,,,,,,,,,.g22"is not prime."<
0 vv < <
1 2
2 ^ v<
3 v1<?>3v4
4 ^ ^
5 > >?> ?>5^
6 v v
7 v9<?>7v6
8 v v<
9 8
10 . > > ^
11 ^<
0 vv_v#:"*********"*25< 01 = x coord
1 8,: > ^ 02 = y coord
2 0>^ ^"* * *"*25<
3 1 > ^
4 p ^"* *** * *"*25<
5 2 > ^
6 0 ^"* * *"*25<
7 2 > ^
8 p ^"* * * *"*25<
9 " > ^
10 O ^"* ***** *"*25< >,v
11 " > ^ |:<"You hit a wall! Game over!"0<
12 0 ^"* * *"*25< >25*,@ |-*84gg20g10<
13 1 > ^v ,*62 pg20g10"O"< <
14 g ^"* * *"*25< >00g"w"-|
15 0 > ^ >00g"e"-| >01g1-01p^
16 2 ^"*********"*250< >00g"s"-| >01g1+01p ^
17 g > " "01g02gp "?",~~$:00p"n"-| >02g2+02p ^
18 >p 62*, ^ >02g2-02p ^
0 Befunge Sources
1 ======= =======
2
3 Name Authour Description
4 ==== ======= ===========
5
6 hello.bf Chris The ubiquitous 'Hello, World!' program.
7
8 hwii.bf Chris Prints out "Hello, World!' forwards, then
9 backwards, then forwards, etc. Demonstrates
10 how one can so easily change the direction of
11 the PC to support their own wicked desires.
12
13 fact.bf Chris Asks for a number, and supplies the
14 factorial of that number.
15
16 random.bf Chris Generates statistically evenly distributed
17 random numbers between 1 and 9.
18
19 chars.bf Kalyna Generates a printable ASCII table, with
20 characters and corresponding codes in
21 decimal.
22
23 drx.bf Chris Like Eliza.
24
25 robot.bf Chris You control an 'O' going through a maze
26 of '*''s. You can type in 'n', 's', 'e',
27 or 'w', and the 'O' travels in that map
28 direction. Bug : you must press return
29 immediately after your choice of direction.
30 The 'game' ends when you hit a '*'.
31
32 maze.bf Chris Back in the old days of Commode 64's, I'd
33 have plenty of fun with this program :
34 flip a coin, if heads, print a fore-slash,
35 if tails, print a back-slash. You may or
36 may not have as much fun as I did with this
37 maze-like pattern generator.
38
39 primes.bf Kalyna Lists the counting numbers, going up from
40 one, and confirms if they are prime or
41 not.
42
43 anagram.bf Kalyna Produces anagrams of words you type in.
44
45 numer.bf Chris Produces numerological equivalents of words
46 you type in.
47
48 toupper.bf Chris Converts letters to upper-case.
49
50
51
52
53 Chris = Chris Pressey
54 Kalyna = Kalyna Zazelenchuk
55 Mike = Mike Veroukis
56 Curt = Curtis Coleman
57
0 Dear Reader,
1
2 Contained in this directory are some recently unearthed documents which
3 sketch a design for a programming language called "Befunge", which,
4 it should be noted, bears little resemblance to the programming language
5 now known as Befunge.
6
7 These documents are dated January 1993, whereas the Befunge-93 documents
8 are dated September 1993. This seems to indicate that the name "Befunge"
9 was in existence for at least eight months before it settled on the
10 programming language that was to become attached to it.
11
12 I make no apologies for the rhetorical excesses found in these documents,
13 nor for the cockamamie approach to language design that they embody.
14
15 Chris Pressey
16 London (THE London)
17 June 6, 2018
0 Befunge
1 =======
2
3 Preliminary design document
4 January 1993
5
6 Chris Pressey
7
8 Introduction
9 ============
10
11 Befunge is (hopefully) a new concept in programming languages. It is still
12 not much more than structured pseudocode, but, IMHO, has potential.
13
14 What makes Befunge 'stand out' from the crowd? Well, for one thing, it's
15 INCREDIBLY terse. For another, it's also INCREDIBLY object-oriented and
16 relaxed. And finally, it can be very ugly to program in. :-)
17
18 Befunge, though, will end up drawing a lot of ideas (and looking a lot
19 like, eventually) from Pascal, C, and PL/I.
20
21 One of the best ways to describe Befunge is 'object-oriented
22 pseudo-assembly', although it is much more versatile than assembly, it is
23 about at that level. (between low- and mid-level... but with objects.)
24
25 This is just a short doc to try to get across what I mean.
26
27 Objects
28 =======
29
30 Objects in Befunge exist in a tree-like hierarchy. Each object is contained
31 within another (parent) object. Some objects cannot contain other objects,
32 but no objects must have children objects either.
33
34 Object Syntax
35 =============
36
37 %xxx (name, reps):(children/data)
38
39 All objects are identified by %xxx, where xxx is three characters.
40 More characters are legal, and in most cases preferred. For example,
41 it is legal to use %fun, although %func is preferred, and %function is
42 quite possible.
43
44 The name is a legal Befunge identifier; so far, a series of ASCII characters,
45 case insensitive, from 'a'..'z', including '_'.
46
47 The reps field in the object declaration defines how many of these objects
48 can be referenced. If omitted, it is presumed to be 1. If omitted in the
49 code, it is presumed to be 0. The range is always 0..reps-1. reps, in the
50 object definition, must be > 0.
51
52 The children/data field (the whole :(c/d) at the end, in fact;
53 %xxx (name, reps) is perfectly legal) is optional, but contains either the
54 object's children (as more object definitions,) or the default data contained
55 within the object.
56
57 Here is a short outline of the objects available in Befunge.
58
59 Byte
60 ====
61 syntax : %byt (name, reps):(initial_value)
62
63 A single (or group : see reps) byte (0..255) value. Generally used as
64 %byte. It cannot have any children; there is only an initial value
65 associated with it.
66
67 eg
68 ==
69 /* Befunge : Pascal : */
70
71 %byte (b):(255); /* var b : byte; begin b := 255; end; */
72 %byte (b, 1):(73); /* same as above */
73 %byte (b, 2):(1000); /* var b : integer; begin b := 1000; end; */
74 %byte (b, 4):(8); /* var b : longint; begin b := 8; end; */
75 %byte (b, 4):(0 1 0 8) /* var b : array [0..3] of byte; */
76 /* begin b[0]:=0;b[1]:=1;b[2]:=0;b[3]:=8; */
77 %byte (b) /* var b : byte; */
78
79 Pointer
80 =======
81 syntax : %ptr (name, reps):(initial_value)
82
83 A de-referenced pointer. It may not contain any objects.
84
85 In code, pointers can be referenced by the following syntax :
86
87 name->object eg, %ptr (p); ... print (p->byt); ...
88
89 eg
90 ==
91 /* Befunge : PL/I : (no std way to do this in Pascal)*/
92
93 %ptr (p); /* Dcl P Pointer; */
94 %ptr (p, 10); /* Dcl P(10) Pointer; */
95
96 Function
97 ========
98 syntax : %fun (name, reps):(objects)
99
100 A shell to use code and local objects. usu. %func. Equivalent to a C
101 function, it can be called inside a %code object (see below). It can
102 be passed a queue of objects and always returns an object. This object
103 may be ignored (a la Pascal's procedures). A %func may contain any
104 object.
105
106 Code
107 ====
108 syntax : %cod (name, reps):(code)
109
110 The code of any %func is contained in the %cod (usu. %code) object.
111 It can contain no other objects. Only three types of code are possible
112 (this is a VERY terse language) :
113 a) Calling another object. %funcs can be called like so :
114 func_name(objects)
115 Data types (%byte, etc) can be 'called'. Calling them with an
116 object in the queue sets that data object to that value and also
117 returns the old value. Calling them with no objects simply
118 returns their current value.
119 b) Looping. The syntax is :
120 while(code1):(code2)
121 code1 is executed. If the return value is not 0, code2 is
122 executed and the loop repeats; else, it breaks.
123 c) Conditional branching. The syntax :
124 if(code1):(code2):(code3)
125 code3 may be omitted. code1 is executed : if the return value
126 is not 0, code2 is executed, else code3 is executed.
127
128 ISSUE : name and reps of code are redundant. What do we do with them?
129
130 Aggregate
131 =========
132 syntax : %agg (name, reps):(objects)
133
134 The aggregate (usu. %aggr) is possibly one of the things that make
135 Befunge... well, so befunged. It takes the place of the record in
136 Pascal, the struct in C, the unit in Pascal, the object in C++, and the
137 module in Modula-2. An aggregate is simply a 'bag' of related objects.
138 Any object may be placed inside an %aggr.
139
140 eg
141 ==
142 /* in Befunge : */
143 %aggr (stack):(
144 %byt (data, 4):(0); /* stack data */
145 %ptr (next); /* pointer to next stack (ll) */
146 );
147
148 /* in Pascal : */
149 var stack : record
150 data : integer;
151 next : ^stack;
152 end;
153
154 Built-in Objects
155 ======== =======
156 All built-in objects (%funcs and data) are kept in the reserved
157 %aggr (internal). Thus, if you create your own %func named print(),
158 you would access the built-in print() via internal.print(), etc.
159 Bounding rules will be discussed later on.
160
161 %funcs
162 ======
163 print() : output to std out all objects given, in bytewise ASCII.
164 print(32), then, would output a space (ASCII 32.)
165 in Befunge, string constants area translated to
166 corresponding ASCII values, so print("Hello!") would work.
167 +() : add all objects given and return value.
168 =(),
169 *(),
170 /() : like +(), you figure them out.
171
172 and(),
173 or(),
174 xor(),
175 not() : boolean/bitwise logic.
176
177 qsize() : returns how many objects are on the local queue.
178 deq() : return the next object off of the local queue.
179 return() : returns the object from the local %func to the caller.
180
181 Directives
182 ==========
183
184 #DEBUG
185 #DEFINE
186 #OBJECT
187 ...will be discussed here.
188
189 Examples
190 ========
191
192 Here is an example 'Hello world' program.
193
194 %func (hello):(
195 %code (
196 print ("Hello, world!")
197 )
198 )
199
200 You, of course, would have to call this from somewhere. A Befunge
201 compiler that was running under an OS that was not Befunge (oh... never
202 mind!) would probably take the topmost object and execute it upon
203 runtime. So, compiling this under a UNIX machine would most likely
204 entail :
205
206 ccu% bf hello.b
207 ccu% hello
208
209 Befunge - How a Compiler might Work
210 ===================================
211
212 Preliminary design document
213 February 1993
214
215 Chris Pressey
216
217 OK, how WOULD it work?
218 ======================
219
220 Well, presuming we COULD get one to work, it would be something like
221 explained in this document.
222
223 First-Pass
224 ==========
225
226 So far as I've got thought out, Befunge is really a pre-processor - it will
227 convert the Befunge language into something that I've termed (for lack of a
228 better term) SLUDGE. We'd then need a SLUDGE->assembly converter. Then
229 assemble it and link it.
230
231 Literal Constants
232 =================
233
234 This will sound weird, but so far as I can tell, it's the best way to
235 handle literal constants. They will be converted as follows :
236
237 "<characters>" will be converted to a byte stream of hex which will
238 be interpreted by the SLUDGE thingy, with a NUL term.
239 eg. " " 2020202000
240 <four spaces> hex for 32, 4 times, then NUL.
241
242 8 08
243 <If the value is 0..255, it is converted to a byte.>
244 <ISSUE : discuss forcing this into n bytes>
245
246 1025 4001
247 <If the value is 256..65535, it is converted to a word.>
248
249 (etc.)
250
251 $7E41 7E41
252 <Should be obvious.>
253
254 Literal Constants, pt II (ok, HERE's the tricky part!)
255 ======================================================
256
257 Now, each literal constant is referenced by Befunge and duplicates are
258 taken out. (eg. printf("hi!"); printf("hi!"); ... the second "hi!" will not
259 be stored as a seperate constant, but will simply reference the first "hi!")
260
261 Each constant is made an object in the internal %aggr literal. (confused?
262 you should be!) So, here's the original "Hello, world!" program :
263
264 %func (hello):(
265 %code (whatever):(
266 printf ("Hello, world!");
267 )
268 );
269
270 Once it passed through Befunge, it would look _something_ like this :
271
272 %aggr (literal):(
273 %byte (strconst_1, $0E):($48656C6C6F2C20776F726C642100);
274 )
275
276 %func (hello):(
277 %code (whatever):(
278 printf (&literal.strconst_1);
279 )
280 );
281
0 /* Example Befunge program. */
1
2 / not a comment /
3 * nor is this ~
4
5 #directive
6
7 %aggr(mine):();
8 %agg(mine):();
9 %aggregate (mine):();
10 %agg (mine):();
11 %aggr(mine);
12 %aggr(mine):()
13 %aggr()/()
14
15 /* This is an example .b (Befunge) file to shove through toy. */
16
17 #debug on /* We'll turn on debugging, as it's the only thing that works :-)
18 */
19 #define one_thing another_thing
20 #erroneous_directive
21
22 #debug off /* Turn debugging off to test it */
23 #define cheese wine /* should not cause a 'definition' hit */
24 #thisdirectiveisverysilly
25
26 #debug on
27
28 %aggr(name):(/* This is just a test for comment removal*/);
29 %aggregate (rank):();
30 %fun (serialnumber):();
31 %int(i):();
32 %zorch(what):();
33 %codeblock(mycode):();
34
35 /* Ha, ha, ha, ha, ha, ha, HA! This is befunged. Totally, completely. */
36
37 /*
38
39 toy.c
40
41 toy parser for Befunge.
42
43 usage : toy <file.b
44
45 Should take objects in the form of %xxx():(), comments in the form of
46 c comments */ /* and Befunge directives in the form #string.
47
48 Jan 1993 Chris Pressey
49
50 */
51
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <ctype.h>
56
57 #define NAME_SIZE 30
58
59 #define OBJ_UNKNOWN 0
60 #define OBJ_AGG 1
61 #define OBJ_FUN 2
62 #define OBJ_COD 3
63 #define OBJ_INT 4
64
65 #define OBJs_AGG 'agg'
66 #define OBJs_FUN 'fun'
67 #define OBJs_COD 'cod'
68 #define OBJs_INT 'int'
69
70 typedef struct bfobject
71 { char *name;
72 int objtype;
73 struct bfobject *next;
74 struct bfobject *child; } *objhead;
75
76 int glob_putback;
77 char glob_putback_char;
78
79 /***********************************************************************/
80 /* get the next character from the input stream, allow virtual putback */
81 /***********************************************************************/
82
83 char ygetchar()
84 {
85 char ch;
86 if (glob_putback)
87 {
88 glob_putback = 0;
89 return (glob_putback_char);
90 } else
91 {
92 scanf("%c", &ch); /* gotta love those segmentation faults */
93 glob_putback_char = ch;
94 return (ch);
95 }
96 }
97
98 /********************************************************************/
99 /* virtually put the last character read back into the input stream */
100 /********************************************************************/
101
102 void putback()
103 {
104 glob_putback = 1;
105 }
106
107 /***********************************************************************/
108 /* get the next character from the input stream, ignore */ /* comments */
109 /***********************************************************************/
110
111 char bgetchar()
112 {
113 char ch;
114 int done;
115
116 ch = ygetchar();
117 if (ch=='/')
118 {
119 ch = ygetchar();
120 if (ch=='*')
121 {
122 ch = ygetchar();
123 done = 0;
124 for(;!done;)
125 {
126 for(;!(ch=='*');) { ch = ygetchar(); }
127 ch = ygetchar();
128 done = (ch=='/');
129 }
130 ch = ygetchar();
131 }
132 }
133 return (ch);
134 }
135
136 /************************************************************/
137 /* get a word (series of alpha chars) from the input stream */
138 /************************************************************/
139 void getword(word, length) char *word; int length;
140 {
141 char ch;
142
143 strcpy (word, "");
144 ch = bgetchar();
145 while((isalpha(ch)) && (strlen(word)<length))
146 {
147 word[strlen(word)+1] = (char)0;
148 word[strlen(word)] = ch;
149 ch = bgetchar();
150 }
151 while(isalpha(ch))
152 {
153 ch = bgetchar();
154 }
155 putback();
156 }
157
158 /*********************/
159 /* skip white spaces */
160 /*********************/
161 void skipwhite()
162 {
163 char ch;
164 ch = bgetchar();
165 while (isspace(ch))
166 {
167 ch = bgetchar();
168 }
169 putback();
170 }
171
172 /*********/
173 /* Debug */
174 /*********/
175 int ddebug;
176 void ydebug(name) char *name;
177 {
178 if (ddebug) { printf("%s\n",name); }
179 }
180
181 /**********************************************************/
182 /* read and display a directive. check for legality (??) */
183 /**********************************************************/
184 void readdirective()
185 {
186 char *dir;
187 char *oof;
188 char ch;
189 int i;
190
191 dir = (char *)malloc(5);
192 oof = (char *)malloc(5);
193 getword (dir, 3);
194 if (!strcmp(dir, "def"))
195 {
196 ydebug("Definition directive");
197 } else
198 if (!strcmp(dir, "deb"))
199 {
200 skipwhite();
201 getword (oof, 3);
202 ddebug=!strcmp(oof,"on");
203 if (ddebug)
204 {
205 printf("DEBUG ON\n");
206 } else
207 {
208 printf("DEBUG OFF\n");
209 }
210 } else
211 {
212 printf("error : unknown directive : %s\n", dir);
213 }
214 free(dir);
215 free(oof);
216 }
217
218 /**********************************************************/
219 /* read and display an object. check for legality (??) */
220 /**********************************************************/
221 void readobject()
222 {
223 char *obj;
224 char ch;
225 int i;
226
227 obj = (char *)malloc(5);
228 getword (obj, 3);
229 if (!strcmp(obj, "agg"))
230 {
231 ydebug("Aggregate object");
232 } else
233 if (!strcmp(obj, "fun"))
234 {
235 ydebug("Function object");
236 } else
237 if (!strcmp(obj, "cod"))
238 {
239 ydebug("Code object");
240 } else
241 if (!strcmp(obj, "int"))
242 {
243 ydebug("Integer object");
244 } else
245 {
246 printf("error : unknown object : %s\n", obj);
247 }
248 free(obj);
249 }
250
251 /********/
252 /* MAIN */
253 /********/
254 int main()
255 {
256 char ch;
257
258 glob_putback = 0;
259 glob_putback_char = (char)0;
260 ddebug = 0;
261
262 for(;!feof(stdin);)
263 {
264 ch = bgetchar();
265 if (ch=='#')
266 {
267 readdirective();
268 }
269 if (ch=='%')
270 {
271 readobject();
272 }
273 }
274 return(0);
275 }