2 Copyright (C) 1990-1992 Free Software Foundation, Inc.
3 Contributed by steve chamberlain @cygnus
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
21 Yet another way of extracting documentation from source.
22 No, I haven't finished it yet, but I hope you people like it better
27 Basically, this is a sort of string forth, maybe we should call it
30 You define new words thus:
31 : <newword> <oldwords> ;
46 #define MIN_CMDLEN 4 /* Minimum length of a command */
54 /* Here is a string type ... */
59 unsigned int write_idx
;
70 init_string_with_size (string_type
*buffer
, unsigned int size
)
72 buffer
->write_idx
= 0;
74 buffer
->ptr
= malloc(size
);
78 init_string (string_type
*buffer
)
80 init_string_with_size(buffer
, DEF_SIZE
);
85 find (string_type
*str
, char *what
)
90 for (i
= 0; i
< str
->write_idx
&& *p
; i
++)
92 if (*p
== str
->ptr
[i
])
102 write_buffer (string_type
*buffer
)
104 fwrite(buffer
->ptr
, buffer
->write_idx
, 1, stdout
);
109 delete_string (string_type
*buffer
)
116 addr (string_type
*buffer
, unsigned int idx
)
118 return buffer
->ptr
+ idx
;
122 at (string_type
*buffer
, unsigned int pos
)
124 if ( pos
>= buffer
->write_idx
)
128 return buffer
->ptr
[pos
];
132 catchar (string_type
*buffer
, char ch
)
134 if (buffer
->write_idx
== buffer
->size
)
137 buffer
->ptr
= realloc(buffer
->ptr
, buffer
->size
);
140 fprintf(stderr
,"Can't allocate memory\n");
145 buffer
->ptr
[buffer
->write_idx
++ ] = ch
;
150 overwrite_string (string_type
*dst
, string_type
*src
)
153 dst
->size
= src
->size
;
154 dst
->write_idx
= src
->write_idx
;
159 catstr (string_type
*dst
, string_type
*src
)
162 for (i
= 0; i
< src
->write_idx
; i
++)
164 catchar(dst
, src
->ptr
[i
]);
170 cattext (string_type
*buffer
, char *string
)
175 catchar(buffer
, *string
);
181 catbuf (string_type
*buffer
, char *buf
, unsigned int len
)
186 catchar(buffer
, *buf
);
194 skip_white_and_stars (string_type
*src
, unsigned int idx
)
196 while (isspace(at(src
,idx
))
197 || (at(src
,idx
) == '*' && at(src
,idx
+1) !='/'))
203 /***********************************************************************/
206 string_type stack
[STACK
];
209 unsigned int idx
= 0; /* Pos in input buffer */
210 string_type
*ptr
; /* and the buffer */
211 typedef void (*stinst_type
)(void);
213 stinst_type sstack
[STACK
];
214 stinst_type
*ssp
= &sstack
[0];
215 uintptr_t istack
[STACK
];
216 uintptr_t *isp
= &istack
[0];
218 typedef uintptr_t *word_type
;
225 struct dict_struct
*next
;
232 typedef struct dict_struct dict_type
;
233 #define WORD(x) static void x(void)
236 exec (dict_type
*word
)
247 stinst_type
*oldpc
= pc
;
249 e
= (dict_type
*)(pc
[1]);
266 *isp
= (uintptr_t)(*pc
);
280 cattext(tos
,*((char **)pc
));
287 /* This function removes everything not inside comments starting on
288 the first char of the line from the string, also when copying
289 comments, removes blank space and leading *'s
290 Blank lines are turned into one blank line
294 remove_noncomments (string_type
*src
, string_type
*dst
)
296 unsigned int idx
= 0;
300 /* Now see if we have a comment at the start of the line */
301 if (at(src
,idx
) == '\n'
302 && at(src
,idx
+1) == '/'
303 && at(src
,idx
+2) == '*')
307 idx
= skip_white_and_stars(src
,idx
);
309 /* Remove leading dot */
310 if (at(src
, idx
) == '.')
313 /* Copy to the end of the line, or till the end of the
317 if (at(src
, idx
) == '\n')
319 /* end of line, echo and scrape of leading blanks */
320 if (at(src
,idx
+1) == '\n')
324 idx
= skip_white_and_stars(src
, idx
);
326 else if (at(src
, idx
) == '*' && at(src
,idx
+1) == '/')
329 cattext(dst
,"\nENDDD\n");
334 catchar(dst
, at(src
, idx
));
342 /* turn foobar name(stuff); into foobar EXFUN(name,(stuff));
356 /* make sure that it's not already exfuned */
357 if(find(tos
,"EXFUN") || find(tos
,"PROTO") || !find(tos
,"(")) {
363 /*Find the open paren*/
364 for (openp
= 0; at(tos
, openp
) != '(' && at(tos
,openp
); openp
++)
368 /* Step back to the fname */
370 while (fname
&& isspace(at(tos
, fname
)))
372 while (fname
&& !isspace(at(tos
,fname
)) && at(tos
,fname
) != '*')
377 for (idx
= 0; idx
< fname
; idx
++)
379 catchar(&out
, at(tos
,idx
));
382 cattext(&out
,"EXFUN(");
383 for (idx
= fname
; idx
< openp
; idx
++)
385 catchar(&out
, at(tos
,idx
));
388 while (at(tos
,idx
) && at(tos
,idx
) !=';')
390 catchar(&out
, at(tos
, idx
));
393 cattext(&out
,");\n");
395 overwrite_string(tos
, &out
);
403 and *} into comments */
405 WORD(translatecomments
)
407 unsigned int idx
= 0;
413 if (at(tos
,idx
) == '{' && at(tos
,idx
+1) =='*')
418 else if (at(tos
,idx
) == '*' && at(tos
,idx
+1) =='}')
425 catchar(&out
, at(tos
, idx
));
431 overwrite_string(tos
, &out
);
438 /* turn everything not starting with a . into a comment */
442 unsigned int idx
= 0;
448 if (at(tos
,idx
) == '\n' && at(tos
,idx
+1) =='*')
453 else if (at(tos
,idx
) == '*' && at(tos
,idx
+1) =='}')
460 catchar(&out
, at(tos
, idx
));
466 overwrite_string(tos
, &out
);
473 /* Mod tos so that only lines with leading dots remain */
477 unsigned int idx
= 0;
483 if (at(tos
, idx
) == '\n' && at(tos
, idx
+1) == '.')
487 while (at(tos
, idx
) && at(tos
, idx
)!='\n')
489 if (at(tos
,idx
) == '{' && at(tos
,idx
+1) =='*')
494 else if (at(tos
,idx
) == '*' && at(tos
,idx
+1) =='}')
501 catchar(&out
, at(tos
, idx
));
513 overwrite_string(tos
, &out
);
518 /* Find lines starting with . and | and put example around them on tos
520 {* into open comment and *} into close comment
527 unsigned int idx
= 0;
533 if (at(tos
, idx
) == '\n'
534 && (at(tos
, idx
+1 ) == '.'
535 || at(tos
,idx
+1) == '|'))
537 cattext(&out
,"\n@smallexample\n");
542 while (at(tos
, idx
) && at(tos
, idx
)!='\n')
544 if (at(tos
,idx
)=='{' && at(tos
,idx
+1) =='*')
549 else if (at(tos
,idx
)=='*' && at(tos
,idx
+1) =='}')
554 else if (at(tos
,idx
) == '{')
559 else if (at(tos
,idx
) == '}')
566 catchar(&out
, at(tos
, idx
));
573 while (at(tos
, idx
) == '\n'
574 && (at(tos
, idx
+1) == '.')
575 || (at(tos
,idx
+1) == '|'));
576 cattext(&out
,"@end smallexample");
580 catchar(&out
, at(tos
, idx
));
585 overwrite_string(tos
, &out
);
592 bulletize: look for bullet item commands at start of line
594 O+ emit @itemize @bullet
595 o emit @item [note lowercase]
607 unsigned int idx
= 0;
611 while (at(tos
, idx
)) {
612 if (at(tos
, idx
) == '\n' && at(tos
, idx
+1) == 'o')
614 if (at(tos
,idx
+2) == '+') {
615 cattext(&out
,"\n@table @code\n");
618 else if (at(tos
,idx
+2) == '-') {
619 cattext(&out
,"\n@end table\n");
622 else if (isspace(at(tos
,idx
+2))) {
623 cattext(&out
,"\n@item ");
627 catchar(&out
, at(tos
, idx
));
633 if (at(tos
, idx
) == '\n' && at(tos
, idx
+1) == 'O')
635 if (at(tos
,idx
+2) == '+') {
636 cattext(&out
,"\n@itemize @bullet\n");
640 else if (at(tos
,idx
+2) == '-') {
641 cattext(&out
,"\n@end itemize\n");
645 catchar(&out
, at(tos
, idx
));
651 catchar(&out
, at(tos
, idx
));
662 /* Turn <<foo>> into @code{foo} in place at TOS
663 Turn <[foo]> into @var{foo} in place at TOS
671 unsigned int idx
= 0;
676 if (at(tos
, idx
) == '<'
677 && at(tos
, idx
+1) == '<'
678 && (!isspace(at(tos
,idx
+ 2)) || at(tos
,idx
+3) == '>'))
680 /* This qualifies as a << startup */
682 cattext(&out
,"@code{");
685 else if (at(tos
, idx
) == '<'
686 && at(tos
, idx
+1) == '['
687 && !isspace(at(tos
,idx
+ 2)))
689 /* This qualifies as a <[ startup */
691 cattext(&out
,"@var{");
693 else if (at(tos
, idx
) == '>'
694 && at(tos
,idx
+1) =='>')
700 else if (at(tos
, idx
) == ']'
701 && at(tos
,idx
+1) =='>')
708 catchar(&out
, at(tos
, idx
));
717 /* A command is all upper case,and alone on a line */
719 iscommand (string_type
*ptr
, unsigned int idx
)
721 unsigned int len
= 0;
723 while (isupper(at(ptr
,idx
)) || at(ptr
,idx
) == '_') {
728 while (at(ptr
,idx
) == ' ') {
733 if(at(ptr
,idx
) == '\n')
735 /* The length check will never fail on a real command
736 * because the commands are screened as the definitions file
738 if (len
>= MIN_CMDLEN
) return 1;
748 copy_past_newline (string_type
*ptr
, unsigned int idx
, string_type
*dst
)
750 while (at(ptr
, idx
) && at(ptr
, idx
) != '\n')
752 catchar(dst
, at(ptr
, idx
));
756 catchar(dst
, at(ptr
, idx
));
762 WORD(icopy_past_newline
)
766 idx
= copy_past_newline(ptr
, idx
, tos
);
772 Take the string at the top of the stack, do some prettying */
777 WORD(kill_bogus_lines
)
787 /* Drop leading nl */
788 while (at(tos
,idx
) == '\n')
794 /* Find the last char */
800 /* find the last non white before the nl */
803 while (idx
&& isspace(at(tos
,idx
)))
807 /* Copy buffer upto last char, but blank lines before and after
813 if (at(tos
,c
) == '\n'
814 && at(tos
,c
+1) == '\n'
815 && at(tos
,c
+2) == '.')
817 /* Ignore two linelines before a dot*/
820 else if (at(tos
,c
) == '.' && sl
)
822 /* remember that this line started with a dot */
825 else if (at(tos
,c
) == '\n'
826 && at(tos
,c
+1) == '\n'
830 /* Ignore two newlines when last line was dot */
833 catchar(&out
, at(tos
,c
));
834 if (at(tos
,c
) == '\n')
838 if (dot
== 2)dot
=1;else dot
= 0;
861 while (at(tos
,idx
)) {
889 catchar(&out
,at(tos
,idx
));
903 /* Change the TOS so that all that is left is the stuff inside the
907 WORD(get_stuff_in_angle
)
909 unsigned int idx
= 0;
915 if (at(tos
,idx
) == '<' && at(tos
,idx
+1) =='<')
919 while (!(at(tos
,idx
) == '>' && at(tos
,idx
+1) == '>'))
921 catchar(&out
, at(tos
, idx
));
930 overwrite_string(tos
, &out
);
935 WORD(get_stuff_in_command
)
940 while (at(ptr
, idx
)) {
941 if (iscommand(ptr
, idx
)) break;
942 idx
= copy_past_newline(ptr
, idx
, tos
);
978 WORD(skip_past_newline
)
981 && at(ptr
,idx
) != '\n')
990 internal_mode
= *(isp
);
997 if (internal_wanted
== internal_mode
)
1007 /* write tos to stderr */
1010 fputs("Warning: ", stderr
);
1011 fwrite(tos
->ptr
, tos
->write_idx
, 1, stderr
);
1012 fputc('\n', stderr
);
1019 nextword (char *string
, char **word
)
1028 while (isspace(*string
) || *string
== '-') {
1031 while (*string
&& *string
!= '\n')
1039 if (!*string
) return 0;
1041 word_start
= string
;
1047 while (*string
!= '"')
1057 while (!isspace(*string
))
1064 *word
= malloc(length
+ 1);
1070 for (idx
= 0; idx
< length
; idx
++)
1073 if (src
[idx
] == '\\' && src
[idx
+1] == 'n')
1079 else *dst
++ = src
[idx
];
1095 lookup_word (char *word
)
1097 dict_type
*ptr
= root
;
1099 if (strcmp(ptr
->word
, word
) == 0) return ptr
;
1103 fprintf(stderr
,"Can't find %s\n",word
);
1115 while (at(ptr
, idx
)) {
1116 /* It's worth looking through the command list */
1117 if (iscommand(ptr
, idx
))
1122 (void) nextword(addr(ptr
, idx
), &next
);
1125 word
= lookup_word(next
);
1132 if(Verbose
) fprintf(stderr
, "CMD '%s'\n", word
->word
);
1137 fprintf(stderr
,"warning, %s is not recognised\n", next
);
1139 skip_past_newline();
1143 else skip_past_newline();
1150 newentry (char *word
)
1152 dict_type
*new = (dict_type
*)malloc(sizeof(dict_type
));
1156 new->code
= (stinst_type
*)malloc(sizeof(stinst_type
));
1157 new->code_length
= 1;
1165 add_to_definition (dict_type
*entry
, stinst_type word
)
1167 if (entry
->code_end
== entry
->code_length
)
1169 entry
->code_length
+= 2;
1171 (stinst_type
*) realloc((char *)(entry
->code
),
1172 entry
->code_length
*sizeof(word_type
));
1174 entry
->code
[entry
->code_end
] = word
;
1176 return entry
->code_end
++;
1186 add_intrinsic (char *name
, void (*func
)(void))
1188 dict_type
*new = newentry(name
);
1189 add_to_definition(new, func
);
1190 add_to_definition(new, 0);
1194 add_var (char *name
)
1196 dict_type
*new = newentry(name
);
1197 add_to_definition(new, push_number
);
1198 add_to_definition(new, (stinst_type
)(&(new->var
)));
1199 add_to_definition(new,0);
1207 compile (char *string
)
1210 /* add words to the dictionary */
1214 string
= nextword(string
, &word
);
1215 while (string
&& *string
&& word
[0])
1217 if (strcmp(word
,"var")==0)
1219 string
=nextword(string
, &word
);
1222 string
=nextword(string
, &word
);
1229 /* Compile a word and add to dictionary */
1230 string
= nextword(string
, &word
);
1231 if(Verbose
) fprintf(stderr
, "Found command '%s'\n", word
);
1232 if(strlen(word
) < MIN_CMDLEN
) {
1233 fprintf(stderr
, "ERROR: Command '%s' is too short ", word
);
1234 fprintf(stderr
, "(MIN_CMDLEN is %d)\n", MIN_CMDLEN
);
1238 ptr
= newentry(word
);
1239 string
= nextword(string
, &word
);
1240 while (word
[0] != ';' )
1247 /* got a string, embed magic push string
1249 add_to_definition(ptr
, push_text
);
1250 add_to_definition(ptr
, (stinst_type
)(word
+1));
1262 /* Got a number, embedd the magic push number
1264 add_to_definition(ptr
, push_number
);
1265 add_to_definition(ptr
, (stinst_type
)atol(word
));
1268 add_to_definition(ptr
, call
);
1269 lookup
= lookup_word(word
);
1271 add_to_definition(ptr
, (stinst_type
)lookup
);
1274 string
= nextword(string
, &word
);
1276 add_to_definition(ptr
,0);
1277 string
= nextword(string
, &word
);
1281 fprintf(stderr
,"syntax error at %s\n",string
-1);
1294 *(uintptr_t *)((isp
[0])) = isp
[-1];
1302 isp
[0] = *(uintptr_t *)(isp
[0]);
1316 read_in (string_type
*str
, FILE *file
)
1322 r
= fread(buff
, 1, sizeof(buff
), file
);
1323 catbuf(str
, buff
, r
);
1328 catbuf(str
, buff
,1);
1337 fprintf(stderr
,"usage: -[i|v] -f macrofile <file >file\n");
1343 main (int ac
, char *av
[])
1352 init_string(&buffer
);
1354 init_string(stack
+0);
1358 add_intrinsic("push_text", push_text
);
1359 add_intrinsic("!", bang
);
1360 add_intrinsic("@", atsign
);
1361 add_intrinsic("hello",hello
);
1362 add_intrinsic("skip_past_newline", skip_past_newline
);
1363 add_intrinsic("catstr", icatstr
);
1364 add_intrinsic("copy_past_newline", icopy_past_newline
);
1365 add_intrinsic("dup", dup_
);
1366 add_intrinsic("remchar", remchar
);
1367 add_intrinsic("get_stuff_in_command", get_stuff_in_command
);
1368 add_intrinsic("get_stuff_in_angle", get_stuff_in_angle
);
1369 add_intrinsic("do_fancy_stuff", do_fancy_stuff
);
1370 add_intrinsic("bulletize", bulletize
);
1371 add_intrinsic("courierize", courierize
);
1372 add_intrinsic("swap", swap
);
1373 add_intrinsic("outputdots", outputdots
);
1374 add_intrinsic("exfunstuff", exfunstuff
);
1375 add_intrinsic("maybecatstr", maybecatstr
);
1376 add_intrinsic("translatecomments", translatecomments
);
1377 add_intrinsic("kill_bogus_lines", kill_bogus_lines
);
1378 add_intrinsic("indent", indent
);
1379 add_intrinsic("internalmode", internalmode
);
1380 add_intrinsic("warn", warn
);
1382 /* Put a nl at the start */
1383 catchar(&buffer
,'\n');
1385 read_in(&buffer
, stdin
);
1386 remove_noncomments(&buffer
, ptr
);
1387 for (i
= 1; i
< ac
; i
++)
1389 if (av
[i
][0] == '-')
1391 if (av
[i
][1] == 'f')
1397 f
= fopen(av
[i
+1],"r");
1400 fprintf(stderr
,"Can't open the input file %s\n",av
[i
+1]);
1403 if(Verbose
) fprintf(stderr
, "Reading -f '%s'\n", av
[i
+1]);
1407 if( compile(b
.ptr
) ) { fclose(f
); exit(1); }
1411 else if (av
[i
][1] == 'i')
1413 internal_wanted
= 1;
1415 else if (av
[i
][1] == 'v')
1422 write_buffer(stack
+0);