home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume6 / cdecl < prev    next >
Text File  |  1986-11-30  |  15KB  |  649 lines

  1. Subject: v06i048:  English<->C translator for C declarations (cdecl)
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.UUCP
  4.  
  5. Submitted by: Chris Torek <cybvax0!harvard!mimsy.umd.edu!gymble!chris>
  6. Mod.sources: Volume 6, Issue 48
  7. Archive-name: cdecl
  8.  
  9. Cdecl has been on the net for a while, but never in mod.sources, or the
  10. archives.  It was written by Graham Ross, once at tektronix!tekmdp!grahamr.
  11. USG sites should add "-DINDEX=strchr" to the CFLAGS entry in the Makefile.
  12.  
  13. --------------------cut--------------------
  14. : Run this shell script with "sh" not "csh"
  15. PATH=/bin:/usr/bin:/usr/ucb:/etc:$PATH
  16. export PATH
  17. echo Extracting Makefile
  18. sed 's/^X//' <<'//go.sysin dd *' >Makefile
  19. # Makefile for cdecl
  20. DESTDIR=
  21. CFLAGS=    -O
  22. LIBS=
  23. MAKE=    make
  24. WHERE=    /usr/local/bin
  25.  
  26. all:    cdecl
  27.  
  28. cdecl:    cdgram.o cdsupp.o
  29.     ${CC} ${CFLAGS} -o $@ cdgram.o cdsupp.o
  30.  
  31. clean:
  32.     rm -f core *.o cdecl cdlex.c cdgram.c
  33.  
  34. install: cdecl
  35.     install -s cdecl ${DESTDIR}${WHERE}/cdecl
  36.  
  37. depend: cdgram.c cdlex.c cdsupp.c
  38.     for i in cdgram.c cdlex.c cdsupp.c; do\
  39.         cc -M ${INCPATH} $$i | sed -e 's, \./, ,' | \
  40.         awk '{ if ($$1 != prev) { if (rec != "") print rec; \
  41.         rec = $$0; prev = $$1; } \
  42.         else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
  43.         else rec = rec " " $$2 } } \
  44.         END { print rec }'; done >makedep
  45.     echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
  46.     echo '$$r makedep' >> eddep
  47.     echo 'w' >>eddep
  48.     cp Makefile Makefile.bak
  49.     ed - Makefile < eddep
  50.     rm eddep makedep
  51.     echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile
  52.     echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile
  53.     echo '# see make depend above' >> Makefile
  54.  
  55. # DO NOT DELETE THIS LINE -- make depend uses it
  56.  
  57. cdgram.o: cdgram.c /usr/include/stdio.h cdlex.c /usr/include/stdio.h
  58. cdgram.o: /usr/include/ctype.h
  59. cdlex.o: cdlex.c /usr/include/stdio.h /usr/include/ctype.h
  60. cdsupp.o: cdsupp.c /usr/include/stdio.h
  61. # DEPENDENCIES MUST END AT END OF FILE
  62. # IF YOU PUT STUFF HERE IT WILL GO AWAY
  63. # see make depend above
  64. //go.sysin dd *
  65. if [ `wc -c < Makefile` != 1290 ]; then
  66.     made=FALSE
  67.     echo error transmitting Makefile --
  68.     echo length should be 1290, not `wc -c < Makefile`
  69. else
  70.     made=TRUE
  71. fi
  72. if [ $made = TRUE ]; then
  73.     chmod 644 Makefile
  74.     echo -n '    '; ls -ld Makefile
  75. fi
  76. echo Extracting cdecl.1
  77. sed 's/^X//' <<'//go.sysin dd *' >cdecl.1
  78. X.TH CDECL 1
  79. X.SH NAME
  80. cdecl \- Compose C declarations
  81. X.SH SYNOPSIS
  82. X.B cdecl
  83. X.SH DESCRIPTION
  84. X.I Cdecl
  85. is a program for encoding and decoding C type-declarations.
  86. It reads standard input for statements in the language described below.
  87. The results are written on standard output.
  88. X.PP
  89. X.I Cdecl's
  90. scope is intentionally small.
  91. It doesn't help you figure out storage classes or initializations.
  92. X.SH "COMMAND LANGUAGE"
  93. There are four statements in the language.
  94. The "declare" statement composes a C type-declaration
  95. from a verbose description.
  96. The "cast" statement composes a C type-cast
  97. as might appear in an expression.
  98. The "explain" statement decodes a C type-declaration, producing a
  99. verbose description.
  100. The "help" statement describes the others.
  101. X.PP
  102. The following grammar describes the language.
  103. In the grammar, words in "<>" are non-terminals,
  104. bare lower-case words are terminals that stand for themselves.
  105. Bare upper-case words are other lexical tokens:
  106. NOTHING means the empty string;
  107. NAME means a C identifier;
  108. NUMBER means a string of decimal digits; and
  109. NL means the new-line character.
  110. X.LP
  111. X.nf
  112. <program>    ::= NOTHING
  113.                | <program> <stat> NL
  114. <stat>       ::= NOTHING
  115.                | declare NAME as <decl>
  116.                | cast NAME into <decl>
  117.                | explain <cdecl>
  118.                | help
  119. <decl>       ::= array of <decl>
  120.                | array NUMBER of <decl>
  121.                | function returning <decl>
  122.                | function ( NAME ) returning <decl>
  123.                | pointer to <decl>
  124.                | <type>
  125. <cdecl>      ::= <cdecl1>
  126.                | * <cdecl>
  127. <cdecl1>     ::= <cdecl1> ( )
  128.                | <cdecl1> [ ]
  129.                | <cdecl1> [ NUMBER ]
  130.                | ( <cdecl> )
  131.                | NAME
  132. <type>       ::= <typename> | <modlist>
  133.                | <modlist> <typename>
  134.                | struct NAME | union NAME | enum NAME
  135. <typename>   ::= int | char | double | float
  136. <modlist>    ::= <modifier> | <modlist> <modifier>
  137. <modifier>   ::= short | long | unsigned
  138. X.fi
  139. X.SH EXAMPLES
  140. To declare an array of pointers to functions like malloc(3), do
  141. X.Ex
  142. declare fptab as array of pointer to function returning pointer to char
  143. X.Ee
  144. The result of this command is
  145. X.Ex
  146. char *(*fptab[])()
  147. X.Ee
  148. When you see this declaration in someone else's code, you
  149. can make sense out of it by doing
  150. X.Ex
  151. explain char *(*fptab[])()
  152. X.Ee
  153. The proper declaration for signal(2) cannot be described in
  154. X.IR cdecl 's
  155. language (it can't be described in C either).
  156. An adequate declaration for most purposes is given by
  157. X.Ex
  158. declare signal as function returning pointer to function returning int
  159. X.Ee
  160. The function declaration that results has two sets of empty parentheses.
  161. The author of such a function might wonder where the parameters go.
  162. X.Ex
  163. declare signal as function (args) returning pointer to function returning int
  164. X.Ee
  165. provides the solution:
  166. X.Ex
  167. int (*signal(args))()
  168. X.Ee
  169. X.SH DIAGNOSTICS
  170. The declare statement tries to point out constructions
  171. that are not supported in C.
  172. Also, certain non-portable constructs are flagged.
  173. X.PP
  174. Syntax errors cause the parser to play dead until a newline is read.
  175. X.SH "SEE ALSO"
  176. Section 8.4 of the C Reference Manual.
  177. X.SH BUGS
  178. The pseudo-English syntax is excessively verbose.
  179. //go.sysin dd *
  180. if [ `wc -c < cdecl.1` != 3231 ]; then
  181.     made=FALSE
  182.     echo error transmitting cdecl.1 --
  183.     echo length should be 3231, not `wc -c < cdecl.1`
  184. else
  185.     made=TRUE
  186. fi
  187. if [ $made = TRUE ]; then
  188.     chmod 444 cdecl.1
  189.     echo -n '    '; ls -ld cdecl.1
  190. fi
  191. echo Extracting cdgram.y
  192. sed 's/^X//' <<'//go.sysin dd *' >cdgram.y
  193. %{
  194. #include <stdio.h>
  195.  
  196. #define    MB_SHORT    0001
  197. #define    MB_LONG        0002
  198. #define    MB_UNSIGNED    0004
  199. #define MB_INT        0010
  200. #define MB_CHAR        0020
  201. #define MB_FLOAT    0040
  202. #define MB_DOUBLE    0100
  203.  
  204. int modbits = 0;
  205. int arbdims = 1;
  206. char *savedtype;
  207. char *savedname;
  208. char *ds(), *cat();
  209. char *index(), *malloc();
  210. char prev;
  211. %}
  212.  
  213. %union {
  214.     char *dynstr;
  215.     struct {
  216.         char *left;
  217.         char *right;
  218.     } halves;
  219. }
  220.  
  221. %token DECLARE CAST INTO AS HELP EXPLAIN
  222. %token FUNCTION RETURNING POINTER TO ARRAY OF
  223. %token <dynstr> NAME NUMBER STRUCTUNION UNSIGNED LONG SHORT
  224. %token <dynstr> INT CHAR FLOAT DOUBLE
  225. %type <dynstr> mod_list tname type modifier
  226. %type <dynstr> cdecl cdecl1 cdims adims c_type
  227. %type <halves> adecl
  228.  
  229. %start prog
  230.  
  231. %%
  232. prog    : /* empty */
  233.         | prog stat
  234.         ;
  235.  
  236. stat    : HELP '\n'
  237.             {
  238.             help();
  239.             }
  240.         | DECLARE NAME AS adecl '\n'
  241.             {
  242.             printf("%s %s%s%s",savedtype,$4.left,$2,$4.right);
  243. #ifdef MKPROGRAM
  244.             if (prev == 'f')
  245.                 printf("\n{\n}\n");
  246.             else
  247.                 printf(";\n");
  248. #else
  249.             printf("\n");
  250. #endif
  251.             free($4.left);
  252.             free($4.right);
  253.             free($2);
  254.             }
  255.         | CAST NAME INTO adecl '\n'
  256.             {
  257.             if (prev == 'f')
  258.                 unsupp("Cast into function");
  259.             else if (prev=='A' || prev=='a')
  260.                 unsupp("Cast into array");
  261.             printf("(%s",savedtype);
  262.             if (strlen($4.left)+strlen($4.right))
  263.                 printf(" %s%s",$4.left,$4.right);
  264.             printf(")%s\n",$2);
  265.             free($4.left);
  266.             free($4.right);
  267.             free($2);
  268.             }
  269.         | EXPLAIN type cdecl '\n'
  270.             { printf("declare %s as %s%s\n",savedname,$3,$2); }
  271.         | '\n'
  272.         | error '\n'
  273.             {
  274.             yyerrok;
  275.             }
  276.         ;
  277.  
  278. cdecl    : cdecl1
  279.         | '*' cdecl
  280.             { $$ = cat($2,ds("pointer to "),NULL); }
  281.         ;
  282.  
  283. cdecl1    : cdecl1 '(' ')'
  284.             { $$ = cat($1,ds("function returning "),NULL); }
  285.         | cdecl1 cdims
  286.             { $$ = cat($1,ds("array "),$2); }
  287.         | '(' cdecl ')'
  288.             { $$ = $2; }
  289.         | NAME
  290.             {
  291.                 savename($1);
  292.                 $$ = ds("");
  293.             }
  294.         ;
  295.  
  296. cdims    : '[' ']'
  297.             { $$ = ds("of "); }
  298.         | '[' NUMBER ']'
  299.             { $$ = cat($2,ds(" of "),NULL); }
  300.         ;
  301.  
  302. adecl    : FUNCTION RETURNING adecl
  303.             {
  304.             if (prev == 'f')
  305.                 unsupp("Function returning function");
  306.             else if (prev=='A' || prev=='a')
  307.                 unsupp("Function returning array");
  308.             $$.left = $3.left;
  309.             $$.right = cat(ds("()"),$3.right,NULL);
  310.             prev = 'f';
  311.             }
  312.         | FUNCTION '(' NAME ')' RETURNING adecl
  313.             {
  314.             if (prev == 'f')
  315.                 unsupp("Function returning function");
  316.             else if (prev=='A' || prev=='a')
  317.                 unsupp("Function returning array");
  318.             $$.left = $6.left;
  319.             $$.right = cat(ds("("),$3,ds(")"));
  320.             $$.right = cat($$.right,$6.right,NULL);
  321.             prev = 'f';
  322.             }
  323.         | ARRAY adims OF adecl
  324.             {
  325.             if (prev == 'f')
  326.                 unsupp("Array of function");
  327.             else if (prev == 'a')
  328.                 unsupp("Inner array of unspecified size");
  329.             if (arbdims)
  330.                 prev = 'a';
  331.             else
  332.                 prev = 'A';
  333.             $$.left = $4.left;
  334.             $$.right = cat($2,$4.right,NULL);
  335.             }
  336.         | POINTER TO adecl
  337.             {
  338.             if (prev == 'a')
  339.                 unsupp("Pointer to array of unspecified dimension");
  340.             if (prev=='a' || prev=='A' || prev=='f') {
  341.                 $$.left = cat($3.left,ds("(*"),NULL);
  342.                 $$.right = cat(ds(")"),$3.right,NULL);
  343.             } else {
  344.                 $$.left = cat($3.left,ds("*"),NULL);
  345.                 $$.right = $3.right;
  346.             }
  347.             prev = 'p';
  348.             }
  349.         | type
  350.             {
  351.             savetype($1);
  352.             $$.left = ds("");
  353.             $$.right = ds("");
  354.             prev = 't';
  355.             }
  356.         ;
  357.  
  358. adims    : /* empty */
  359.             {
  360.             arbdims = 1;
  361.             $$ = ds("[]");
  362.             }
  363.         | NUMBER
  364.             {
  365.             arbdims = 0;
  366.             $$ = cat(ds("["),$1,ds("]"));
  367.             }
  368.         ;
  369.  
  370. type    : tinit c_type
  371.             { mbcheck(); $$ = $2; }
  372.         ;
  373.  
  374. tinit    : /* empty */
  375.             { modbits = 0; }
  376.         ;
  377.  
  378. c_type    : mod_list
  379.             { $$ = $1; }
  380.         | tname
  381.             { $$ = $1; }
  382.         | mod_list tname
  383.             { $$ = cat($1,ds(" "),$2); }
  384.         | STRUCTUNION NAME
  385.             { $$ = cat($1,ds(" "),$2); }
  386.         ;
  387.  
  388. tname    : INT
  389.             { modbits |= MB_INT; $$ = $1; }
  390.         | CHAR
  391.             { modbits |= MB_CHAR; $$ = $1; }
  392.         | FLOAT
  393.             { modbits |= MB_FLOAT; $$ = $1; }
  394.         | DOUBLE
  395.             { modbits |= MB_DOUBLE; $$ = $1; }
  396.         ;
  397.  
  398. mod_list: modifier
  399.             { $$ = $1; }
  400.         | mod_list modifier
  401.             { $$ = cat($1,ds(" "),$2); }
  402.         ;
  403.  
  404. modifier: UNSIGNED
  405.             { modbits |= MB_UNSIGNED; $$ = $1; }
  406.         | LONG
  407.             { modbits |= MB_LONG; $$ = $1; }
  408.         | SHORT
  409.             { modbits |= MB_SHORT; $$ = $1; }
  410.         ;
  411. %%
  412. #include "cdlex.c"
  413.  
  414. #define LORS    (MB_LONG|MB_SHORT)
  415. #define UORL    (MB_UNSIGNED|MB_LONG)
  416. #define UORS    (MB_UNSIGNED|MB_SHORT)
  417. #define CORL    (MB_CHAR|MB_LONG)
  418. #define CORS    (MB_CHAR|MB_SHORT)
  419. #define CORU    (MB_CHAR|MB_UNSIGNED)
  420.  
  421. mbcheck()
  422. {
  423.     if ((modbits&LORS) == LORS)
  424.         unsupp("conflicting 'short' and 'long'");
  425.     if ((modbits&UORL) == UORL)
  426.         unport("unsigned with long");
  427.     if ((modbits&UORS) == UORS)
  428.         unport("unsigned with short");
  429.     if ((modbits&CORL) == CORL)
  430.         unsupp("long char");
  431.     if ((modbits&CORS) == CORS)
  432.         unsupp("short char");
  433.     if ((modbits&CORU) == CORU)
  434.         unport("unsigned char");
  435. }
  436.  
  437. savetype(s)
  438. char *s;
  439. {
  440.     savedtype = s;
  441. }
  442.  
  443. savename(s)
  444. char *s;
  445. {
  446.     savedname = s;
  447. }
  448. //go.sysin dd *
  449. if [ `wc -c < cdgram.y` != 4726 ]; then
  450.     made=FALSE
  451.     echo error transmitting cdgram.y --
  452.     echo length should be 4726, not `wc -c < cdgram.y`
  453. else
  454.     made=TRUE
  455. fi
  456. if [ $made = TRUE ]; then
  457.     chmod 644 cdgram.y
  458.     echo -n '    '; ls -ld cdgram.y
  459. fi
  460. echo Extracting cdlex.l
  461. sed 's/^X//' <<'//go.sysin dd *' >cdlex.l
  462. %{
  463. #include <ctype.h>
  464.  
  465. char *visible();
  466. %}
  467. N    [0-9]
  468. A    [A-Z_a-z]
  469. AN    [0-9A-Z_a-z]
  470. %%
  471. array        return ARRAY;
  472. as            return AS;
  473. cast        return CAST;
  474. declare        return DECLARE;
  475. explain        return EXPLAIN;
  476. function    return FUNCTION;
  477. help        return HELP;
  478. into        return INTO;
  479. of            return OF;
  480. pointer        return POINTER;
  481. returning    return RETURNING;
  482. to            return TO;
  483.  
  484. char        { yylval.dynstr = ds(yytext); return CHAR; }
  485. double        { yylval.dynstr = ds(yytext); return DOUBLE; }
  486. enum        { yylval.dynstr = ds(yytext); return STRUCTUNION; }
  487. float        { yylval.dynstr = ds(yytext); return FLOAT; }
  488. int            { yylval.dynstr = ds(yytext); return INT; }
  489. long        { yylval.dynstr = ds(yytext); return LONG; }
  490. short        { yylval.dynstr = ds(yytext); return SHORT; }
  491. struct        { yylval.dynstr = ds(yytext); return STRUCTUNION; }
  492. union        { yylval.dynstr = ds(yytext); return STRUCTUNION; }
  493. unsigned    { yylval.dynstr = ds(yytext); return UNSIGNED; }
  494.  
  495. {A}{AN}*    { yylval.dynstr = ds(yytext); return NAME; }
  496. {N}+        { yylval.dynstr = ds(yytext); return NUMBER; }
  497.  
  498. [\t ]        ;
  499. [*[\]()\n]        return *yytext;
  500. X.            {
  501.                 printf("bad character '%s'\n",visible(*yytext));
  502.                 return *yytext;
  503.             }
  504. %%
  505. char *
  506. visible(c)
  507. {
  508.     static char buf[5];
  509.  
  510.     c &= 0377;
  511.     if (isprint(c)) {
  512.         buf[0] = c;
  513.         buf[1] = '\0';
  514.     } else
  515.         sprintf(buf,"\\%02o",c);
  516.     return buf;
  517. }
  518. //go.sysin dd *
  519. if [ `wc -c < cdlex.l` != 1273 ]; then
  520.     made=FALSE
  521.     echo error transmitting cdlex.l --
  522.     echo length should be 1273, not `wc -c < cdlex.l`
  523. else
  524.     made=TRUE
  525. fi
  526. if [ $made = TRUE ]; then
  527.     chmod 644 cdlex.l
  528.     echo -n '    '; ls -ld cdlex.l
  529. fi
  530. echo Extracting cdsupp.c
  531. sed 's/^X//' <<'//go.sysin dd *' >cdsupp.c
  532. #include <stdio.h>
  533. char *malloc();
  534.  
  535. main()
  536. {
  537.     yyparse();
  538. }
  539.  
  540. unsupp(s)
  541. char *s;
  542. {
  543.     printf("Warning: Unsupported in C -- %s\n",s);
  544. }
  545.  
  546. unport(s)
  547. char *s;
  548. {
  549.     printf("Warning: Non-portable construction -- %s\n",s);
  550. }
  551.  
  552. yyerror(s)
  553. char *s;
  554. {
  555.     printf("%s\n",s);
  556. }
  557.  
  558. yywrap()
  559. {
  560.     return 1;
  561. }
  562.  
  563. X/*
  564.  * Support for dynamic strings:
  565.  * cat creates a string from three input strings.
  566.  * The input strings are freed by cat (so they better have been malloced).
  567.  * ds makes a malloced string from one that's not.
  568.  */
  569.  
  570. char *
  571. cat(s1,s2,s3)
  572. char *s1,*s2,*s3;
  573. {
  574.     register char *newstr;
  575.     register unsigned len = 0;
  576.  
  577.     if (s1 != NULL) len = strlen(s1) + 1;
  578.     if (s2 != NULL) len += strlen(s2);
  579.     if (s3 != NULL) len += strlen(s3);
  580.     newstr = malloc(len);
  581.     if (s1 != NULL) {
  582.         strcpy(newstr,s1);
  583.         free(s1);
  584.     }
  585.     if (s2 != NULL) {
  586.         strcat(newstr,s2);
  587.         free(s2);
  588.     }
  589.     if (s3 != NULL) {
  590.         strcat(newstr,s3);
  591.         free(s3);
  592.     }
  593.     return newstr;
  594. }
  595.  
  596. char *
  597. ds(s)
  598. char *s;
  599. {
  600.     register char *p;
  601.  
  602.     p = malloc((unsigned)(strlen(s)+1));
  603.     strcpy(p,s);
  604.     return p;
  605. }
  606.  
  607. static char *helptext[] = {
  608.     "[] means optional; {} means 1 or more; <> means defined elsewhere\n",
  609.     "command:\n",
  610.     "  declare <name> as <english>\n",
  611.     "  cast <name> into <english>\n",
  612.     "  explain <gibberish>\n",
  613.     "english:\n",
  614.     "  function [( <name> )] returning <english>\n",
  615.     "  array [<number>] of <english>\n",
  616.     "  pointer to <english>\n",
  617.     "  <type>\n",
  618.     "type:\n",
  619.     "  [{<modifier>}] <C-type>\n",
  620.     "  {<modifier>} [<C-type>]\n",
  621.     "  <sue> <name>\n",
  622.     "name is a C identifier\n",
  623.     "gibberish is a C declaration\n",
  624.     "C-type is int, char, double or float\n",
  625.     "modifier is short, long or unsigned\n",
  626.     "sue is struct, union or enum\n",
  627.     NULL
  628. };
  629.  
  630. help()
  631. {
  632.     register char **p;
  633.  
  634.     for (p=helptext; *p!=NULL; p++)
  635.             printf("\t%s",*p);
  636. }
  637. //go.sysin dd *
  638. if [ `wc -c < cdsupp.c` != 1759 ]; then
  639.     made=FALSE
  640.     echo error transmitting cdsupp.c --
  641.     echo length should be 1759, not `wc -c < cdsupp.c`
  642. else
  643.     made=TRUE
  644. fi
  645. if [ $made = TRUE ]; then
  646.     chmod 644 cdsupp.c
  647.     echo -n '    '; ls -ld cdsupp.c
  648. fi
  649.