[comp.sources.misc] v06i068: Lex programme to convert pANS to Classic C

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (03/21/89)

Posting-number: Volume 6, Issue 68
Submitted-by: lupton@uhccux.uhcc.Hawaii.Edu (Robert Lupton )
Archive-name: deansi

[Also see "agcpp", as posted to comp.os.minix.  ++bsa]

My postnews spat this out (`error 11' -- ?), so here it is by mail.
[Ummm, sounds like a segmentation violation.  Contact your local guru.  ++bsa]

Here is a simple-minded Lex programme to convert ANSI to Classic C,
or at least to try. It will convert prototypes external to functions
to extern declarations, convert function declarations from the form
"foo(int a,char *b)" to "foo(a,b) int a; char *b;" and remove a couple
of keywords (volatile, const). No attempt is made to deal with
pre-processor incompatibilities.

You are welcome to copy, modify, or (even |-) improve the code,
providing that my name remains on it, you don't make money, and these
conditions remain on the fruits of your labours. Also, please post
any significant improvements.

			Robert Lupton
			
: =-=-=-=-=-=-=-=-=-=-= Cut Here =-=-=-=-=-=-=-=-=-=-=
PATH=/bin:/usr/bin:/usr/ucb:/etc:$PATH
export PATH
echo Extracting Makefile
if [ -w Makefile ]; then
	echo File already exists - saving as Makefile.old
	mv Makefile Makefile.old
	chmod 444 Makefile.old
fi
sed 's/^X//' <<'//go.sysin dd *' >Makefile
#
# Take an ansi programme, and prepare it for a K&R1 compiler.
# No attempt is made to deal with preprocessor differences,
# but some keywords are deleted (volatile, const), and declarations
# are modified to be acceptable
#
CFLAGS = -g
#
deansi : deansi.o
	cc -o deansi deansi.o -ll
	@- rm -f deansi.o
#
tidy :
	rm -f *~ deansi.c *.o core a.out
empty : tidy
	rm -f deansi
//go.sysin dd *
if [ `wc -c < Makefile` != 374 ]; then
made=FALSE
echo error transmitting Makefile --
echo length should be 374, not `wc -c < Makefile`
else
	made=TRUE
fi
if [ $made = TRUE ]; then
	chmod 644 Makefile
	echo -n  ; ls -ld Makefile
fi
echo Extracting deansi.l
if [ -w deansi.l ]; then
	echo File already exists - saving as deansi.l.old
	mv deansi.l deansi.l.old
	chmod 444 deansi.l.old
fi
sed 's/^X//' <<'//go.sysin dd *' >deansi.l
%%
%{
X/*
 * Syntax: deansi [ file ]
 *
 * This lex programme takes an ANSI style (prototyped) function declaration,
 * and makes it acceptable to a K&R-1 style (`Classic') compiler. It assumes
 * that the last valid name in a declaration is the name of the variable.
 *
 * Varargs functions (with ...) are not understood.
 *
 * Prototypes ending in a ; are converted to old-style declarations
 *
 * A couple of ANSI keywords are deleted (const, volatile)
 *
 * No attempt is made to deal with preprocessor directives
 *
 * Anyone is permitted to copy, modify, or improve this programme,
 * providing that this notice appears on the final result, and that
 * they don't make any money out of it. 
 * 
 *			Robert Lupton
 */
#include <ctype.h>
#define isok(C) (isalnum(C) || (C) == '_')

int brace = 0,				/* level of {} grouping */
    in_comment = 0;			/* am I in a comment? */

%}

\([ \t]*void[ \t]*\)	{		/* functions declared (void) */
		   if(brace == 0) {
		      printf("()");
		   } else {
		      REJECT;
		   }
		}

\([^{};]*\)[ \t]*;	{		/* prototypes */
		   int i,
		       paren = 0;	/* level of parens */

		   if(brace == 0 && !in_comment) {
		      for(i = 0;i < yyleng;i++) {
			 if(paren == 0) putchar(yytext[i]);
			 if(yytext[i] == '(') paren++;
			 if(yytext[i] == ')') {
			    paren--;
			    if(paren == 0) putchar(')');
			 }
		      }
		   } else {
		      REJECT;
		   }
		}

\([^{};]*\)	{			/* declarations */
		   char *decl;
		   int i,j,k;

		   if(brace == 0 && !in_comment) {
		      /* printf("<%s>",yytext); */
		      yytext[--yyleng] = '\0'; /* strip closing ')' */

		      putchar('(');
		      for(j = 1;j < yyleng;) {
	      	         for(i = 0,decl = &yytext[j];
			     	decl[i] != '\0' && decl[i] != ',';i++) ;
			 j += i + 1;
	      	         for(;!isok(decl[i]);i--) ;
	      	         for(k = 0;isok(decl[i - k]);k++) ;
			 printf("%.*s",k,&decl[i - k + 1]);
			 if(j < yyleng - 1) putchar(',');
		      }
		      printf(")\n");

		      for(j = 1;j < yyleng;) {
	      	         for(i = 0,decl = &yytext[j];
				     decl[i] != ',' && decl[i] != '\0';i++) ;
			 
			 printf("%.*s;",i,decl);
			 j += i + 1;
			 if(j < yyleng - 1) putchar('\n');
		      }
		   } else {
		      REJECT;
		   }
		}

"/*"		{ in_comment = 1; ECHO; }

"*/"		{ in_comment = 0; ECHO; }

\"[^"]*\"	{ ECHO; }

"{"		{ if(!in_comment) brace++; ECHO; }

"}"		{ if(!in_comment) brace--; ECHO; }

const[ \t]*	|
volatile[ \t]*	;

[a-z]*		|
.|\n		ECHO;
%%
#include <stdio.h>

main(ac,av)
int ac;
char **av;
{
   if(ac > 1) {
      if(freopen(av[1],"r",stdin) == NULL) {
	 fprintf(stderr,"Can't open %s\n",av[1]);
	 exit(-1);
      }
   }
   yylex();
}
//go.sysin dd *
if [ `wc -c < deansi.l` != 2666 ]; then
made=FALSE
echo error transmitting deansi.l --
echo length should be 2666, not `wc -c < deansi.l`
else
	made=TRUE
fi
if [ $made = TRUE ]; then
	chmod 644 deansi.l
	echo -n  ; ls -ld deansi.l
fi
echo Extracting tst.c
if [ -w tst.c ]; then
	echo File already exists - saving as tst.c.old
	mv tst.c tst.c.old
	chmod 444 tst.c.old
fi
sed 's/^X//' <<'//go.sysin dd *' >tst.c
X/*
 * A test (with parentheses)
 */
extern int main(register int,char **),
	   func(void);
static int func2(void (*my_func)(),const char *);

main(register int ac,char **av)
{
   volatile int interrupt;
   const char *ptr = "World\n";

   (void)func2(func,ptr);
}

int
func(void)
{
   printf("Hello ");
}

static int
func2(void (*my_func)(),const char *s)
{
   (*my_func)();
   return(printf("%s",s));
}
//go.sysin dd *
if [ `wc -c < tst.c` != 404 ]; then
made=FALSE
echo error transmitting tst.c --
echo length should be 404, not `wc -c < tst.c`
else
	made=TRUE
fi
if [ $made = TRUE ]; then
	chmod 644 tst.c
	echo -n  ; ls -ld tst.c
fi