From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- support/rail/rail.c | 726 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 726 insertions(+) create mode 100644 support/rail/rail.c (limited to 'support/rail/rail.c') diff --git a/support/rail/rail.c b/support/rail/rail.c new file mode 100644 index 0000000000..c0f0b3851e --- /dev/null +++ b/support/rail/rail.c @@ -0,0 +1,726 @@ +/* + * rail.c - railroad diagram utility + * + * 09-Jul-1990 L. Rooijakkers + * 09-Oct-1990 L. Rooijakkers + * 07-Feb-1991 L. Rooijakkers indexing, embedded options + * 08-Feb-1991 L. Rooijakkers small mods for version 1.0 #0 + * 12-Feb-1991 L. Rooijakkers minor portability fixes + * 28-Jun-1994 K. Barthelmann minor changes + * 12-Jan-1997 K. Barthelmann minor portability improvements + * 19-May-1998 J. Olsson Added suport for arrow heads. + * + */ + +#ifndef lint +static char SccsId[]="@(#)rail 26-Jul-1998"; +#endif + +#define USAGE "usage: %s [-+acdit] [file]\n" + +#include +#include +#include + +#include "patchlevel.h" +#include "rail.h" +#include "gram.h" + +static char *myname; /* program name */ + +static char *file; /* input file */ +extern FILE *yyin; /* lex input stream */ + +static char *outfile; /* output file */ +FILE *outf; /* output stream */ + +static int newline; /* stdout requires a newline */ + +static IDTYPE *idlist; /* identifier list */ + +IDTYPE *errorid; /* identifier for errors */ + +/* options */ + +int altstar; /* alternate star */ +int arrowheads; /* produce arrowheads on the rails */ +static int chkgram; /* check grammar */ +static int treelist; /* list rule trees */ +static int genindex; /* generate index entry for left hand sides */ + +#ifdef YYDEBUG +extern int yydebug; /* show yacc debugging */ +#endif + +int anonymous; /* anonymous rules */ + +main(argc,argv) +unsigned argc; +char *argv[]; +{ + char *arg, **argp; + unsigned len; + + printf("This is Rail, Version %s #%d\n",VERSION,PATCHLEVEL); + newline=0; + + myname=argv[0]; + + for(argp = &argv[1];(arg = *argp)!=NULL;argp++) { + if(*arg!='-' && *arg!='+') + break; + if(setopt(*arg,arg+1)==0) + usage(); + } + + if(arg!=NULL && *++argp!=NULL) + usage(); + + if(arg==NULL) { + file="stdin"; + outfile="stdout"; + yyin=stdin; + outf=stdout; + } else { + len=strlen(arg)+5; + file=mcheck(malloc(len)); + outfile=mcheck(malloc(len)); + strcat(strcpy(file,arg),".rai"); + strcat(strcpy(outfile,arg),".rao"); + if((yyin=fopen(file,"r"))==NULL) { + perror(file); + exit(1); + } + if((outf=fopen(outfile,"w"))==NULL) { + perror(outfile); + exit(1); + } + } + + printf("(%s",file); + newline=1; + + line=1; + + fprintf(outf,"%% This file was generated by '%s' from '%s'\n",myname,file); + + if(yyparse()!=0) + exit(1); + + printf(")\n"); + newline=0; + + file=NULL; + + if(chkgram) { + checkdefs(); + if(anonymous) + error("unnamed rules are present",(char *)NULL); + } + + exit(0); + /*NOTREACHED*/ +} + +int setopt(c,s) +char c, *s; +{ + int set; + + set = c=='-'; + + while(*s!='\0') { + + switch(*s++) { + + case 'a': + altstar=set; + break; + + case 'c': + chkgram=set; + break; + + case 'd': +#ifdef YYDEBUG + yydebug=set; +#endif + break; + + case 'i': + genindex=set; + break; + + case 't': + treelist=set; + break; + + case 'h': + arrowheads=set; + break; + + default: + return 0; + } + } + + return 1; +} + +usage() +{ + fprintf(stderr,USAGE,myname); + exit(1); +} + +/* error routine for yyparse() */ + +yyerror(s) +char *s; +{ + fatal("%s",s); +} + +/* wrap-up routine for yylex() */ + +yywrap() +{ + return(1); +} + +/* check for non-NULL pointer */ + +char *mcheck(s) +char *s; +{ + if(s==NULL) + fatal("out of memory",(char *)NULL); + + return(s); +} + +/* make a new body */ + +BODYTYPE *newbody(kind,body1,body2) +int kind; +BODYTYPE *body1, *body2; +{ + BODYTYPE *body; + + body=(BODYTYPE *)mcheck(malloc(sizeof(BODYTYPE))); + body->kind=kind; + body->nlist=0; + body->done=0; + body->id=NULL; + body->text=NULL; + body->annot=NULL; + + if(body1!=NULL) + body->list[body->nlist++]=body1; + + if(body2!=NULL) + body->list[body->nlist++]=body2; + + return(body); +} + +/* free a body recursively */ + +freebody(body) +BODYTYPE *body; +{ + int i; + + if(body==NULL) + return; + + for(i=0;inlist;i++) + freebody(body->list[i]); + + if(body->text!=NULL) { + /* should free text here */ + } + + free((char *)body); +} + +/* test if a body is empty */ + +int isemptybody(body) +BODYTYPE *body; +{ + return(body==NULL || body->kind==EMPTY); +} + +/* add to a body list */ + +static addlist(body1,body2) +BODYTYPE *body1, *body2; +{ + if(body1->nlist>=MAXLIST) { + yyerror("list too long"); + } else + body1->list[body1->nlist++]=body2; +} + +/* add two body lists (for CAT, BAR, PLUS) */ + +BODYTYPE *addbody(kind,body1,body2) +int kind; +BODYTYPE *body1, *body2; +{ + BODYTYPE *body; + int i; + + if(body1->kind==kind && !(kind==BAR && body1->done) ) { + body=body1; + } else { + body=newbody(kind,NULLBODY,NULLBODY); + addlist(body,body1); + } + + if(body2->kind==kind && !(kind==BAR && body2->done) ) { + for(i=0;inlist;i++) + addlist(body,body2->list[i]); + free((char *)body2); + } else { + addlist(body,body2); + } + + return(body); +} + +/* reverse all concatenations (for PLUS) */ + +BODYTYPE *revbody(body) +BODYTYPE *body; +{ + int i,j; + BODYTYPE *tmp; + + if(body->kind==CAT) { + for(i=0,j=body->nlist-1;ilist[i]; + body->list[i]=body->list[j]; + body->list[j]=tmp; + } + } + + for(i=0;inlist;i++) + body->list[i]=revbody(body->list[i]); + + return(body); +} + +/* print a body for debugging */ + +prtbody(indent,body) +int indent; +BODYTYPE *body; +{ + int i; + + fprintf(outf,"%% "); + + for(i=0;ikind) { + + case EMPTY: + fprintf(outf,"EMPTY"); + break; + + case CAT: + fprintf(outf,"CAT"); + break; + + case BAR: + fprintf(outf,"BAR"); + break; + + case PLUS: + fprintf(outf,"PLUS"); + break; + + case ANNOTE: + fprintf(outf,"ANNOTE [%s]",body->text); + break; + + case IDENT: + fprintf(outf,"IDENT %s",body->id->name); + break; + + case CR: + fprintf(outf,"CR"); + break; + + case STRNG: + fprintf(outf,"STRNG '%s'",body->text); + break; + + default: + fprintf(outf,"UNKNOWN"); + break; + } + + fprintf(outf," y=%d nexty=%d\n",body->ystart,body->ynext); + + for(i=0;inlist;i++) + prtbody(indent+1,body->list[i]); + } +} + +/* output a body */ + +outbody(id,body) +IDTYPE *id; +BODYTYPE *body; +{ + posbody(body,0); + + if(treelist) + prtbody(0,body); + + fprintf(outf,"\\rail@begin{%d}{",body->ynext); + if(id!=NULL) { + fprintf(outf,"%s",id->name); + } + fprintf(outf,"}\n"); + + if (arrowheads) { + fmtbody(body,"",RIGHT_ARROW); + fprintf(outf,"\\rail@vend\n"); + } + else { + fmtbody(body,"",NO_ARROW); + fprintf(outf,"\\rail@end\n"); + } +} + +/* format a body */ + +fmtbody(body,cent,arrow) +BODYTYPE *body; +char *cent; +char arrow; +{ + BODYTYPE *body1; + int i; + char *next; + + switch(body->kind) { + + case EMPTY: + break; + + case CAT: + for(i=0;inlist;i++) + fmtbody(body->list[i],"",arrow); + break; + + case BAR: + next="\\rail@bar\n"; + for(i=0;inlist;i++) { + body1=body->list[i]; + fprintf(outf,next,body1->ystart); + next="\\rail@nextbar{%d}\n"; + fmtbody(body1,"",arrow); + } + fprintf(outf,"\\rail@endbar\n"); + break; + + case PLUS: + fprintf(outf,"\\rail@plus\n"); + + if (arrow == NO_ARROW) + fmtbody(body->list[0],"",arrow); + else if (body->list[0]->kind == EMPTY) { + arrow = arrow == RIGHT_ARROW ? LEFT_ARROW : RIGHT_ARROW; + fmtbody(body->list[0],"",arrow); + } + else { + fmtbody(body->list[0],"",arrow); + arrow = arrow == RIGHT_ARROW ? LEFT_ARROW : RIGHT_ARROW; + } + + body1=body->list[1]; + fprintf(outf,"\\rail@nextplus{%d}\n",body1->ystart); + + fmtbody(body1,"c",arrow); + + fprintf(outf,"\\rail@endplus\n"); + break; + + case ANNOTE: + fprintf(outf,"\\rail@annote[%s]\n",body->text); + break; + + case IDENT: + if(body->id->kind==TERM) + if (arrow == NO_ARROW) + fprintf(outf,"\\rail@%stoken{%s}",cent,body->id->name); + else + fprintf(outf,"\\rail@%c%stoken{%s}",arrow,cent,body->id->name); + else + if (arrow == NO_ARROW) + fprintf(outf,"\\rail@%snont{%s}",cent,body->id->name); + else + fprintf(outf,"\\rail@%c%snont{%s}",arrow,cent,body->id->name); + + fprintf(outf,"[%s]\n",body->annot!=NULL?body->annot:""); + break; + + case CR: + fprintf(outf,"\\rail@cr{%d}\n",body->ynext-1); + break; + + case STRNG: + if (arrow == NO_ARROW) + fprintf(outf,"\\rail@%sterm{%s}",cent,body->text); + else + fprintf(outf,"\\rail@%c%sterm{%s}",arrow,cent,body->text); + fprintf(outf,"[%s]\n",body->annot!=NULL?body->annot:""); + break; + + default: + fprintf(outf,"\\rail@unknown\n"); + break; + } +} + +/* position body (fill in height and ystart) */ + +posbody(body,ystart) +BODYTYPE *body; +{ + BODYTYPE *body1; + int i; + + switch(body->kind) { + + case CAT: + body->ystart=ystart; + body->ynext=ystart+1; + + for(i=0;inlist;i++) { + body1=body->list[i]; + if(body1->kind==CR) { + body1->ystart=ystart; + body1->ynext=body->ynext+2; + ystart=body1->ynext-1; + } else + posbody(body1,ystart); + if(body1->ynext>body->ynext) + body->ynext=body1->ynext; + } + break; + + case BAR: + case PLUS: + body->ystart=ystart; + body->ynext=ystart+1; + + for(i=0;inlist;i++) { + body1=body->list[i]; + posbody(body1,ystart); + ystart=body1->ynext; + if(body1->ynext>body->ynext) + body->ynext=body1->ynext; + } + break; + + case CR: + body->ystart=ystart; + body->ynext=ystart+3; + break; + + case EMPTY: + case ANNOTE: + case IDENT: + case STRNG: + default: + body->ystart=ystart; + body->ynext=ystart+1; + break; + } +} + +/* output an index entry */ + +outindex(id) +IDTYPE *id; +{ + if(id!=NULL) + fprintf(outf,"\\rail@index{%s}\n",id->name); +} + +/* make a new rule list */ + +RULETYPE *newrule(id,body) +IDTYPE *id; +BODYTYPE *body; +{ + RULETYPE *rule; + + rule=(RULETYPE *)mcheck(malloc(sizeof(RULETYPE))); + rule->id=id; + rule->body=body; + rule->next=NULL; + + return(rule); +} + +/* free a rule list */ + +freerule(rule) +RULETYPE *rule; +{ + RULETYPE *rulep; + + while(rule!=NULL) { + rulep=rule->next; + freebody(rule->body); + free((char *)rule); + rule=rulep; + } +} + +/* add two rule lists */ + +RULETYPE *addrule(rule1,rule2) +RULETYPE *rule1, *rule2; +{ + RULETYPE *rulep; + + if(rule1==NULL) + return(rule2); + + for(rulep=rule1;rulep->next!=NULL;rulep=rulep->next) + ; + + rulep->next=rule2; + + return(rule1); +} + +/* output a rule list */ + +outrule(rule) +RULETYPE *rule; +{ + while(rule!=NULL) { + + if(genindex) + outindex(rule->id); + + outbody(rule->id,rule->body); + + rule=rule->next; + } +} + +/* look up an identifier */ + +IDTYPE *lookup(name) +char *name; +{ + IDTYPE *idp, **idq; + + for(idq = &idlist;(idp = *idq)!=NULL;idq = &idp->next) + if(strcmp(name,idp->name)==0) + return(idp); + + idp=(IDTYPE *)mcheck(malloc(sizeof(IDTYPE))); + + idp->name=mcheck(malloc((unsigned)strlen(name)+1)); + strcpy(idp->name,name); + idp->next=NULL; + idp->kind=UNKNOWN; + + *idq=idp; + + return(idp); +} + +/* delete an identifier */ + +delete(id) +IDTYPE *id; +{ + IDTYPE *idp, **idq; + + for(idq = &idlist;(idp = *idq)!=NULL;idq = &idp->next) { + if(idp==id) { + *idq = idp->next; + free(idp->name); + free((char *)idp); + return; + } + } +} + +/* check that there are no undefined identifiers */ + +checkdefs() +{ + IDTYPE *id; + + for(id=idlist;id!=NULL;id=id->next) + if(id->kind==TOKEN) + undef(id); +} + +/* complain about an undefined identifier */ + +undef(id) +IDTYPE *id; +{ + if(chkgram) + error("undefined identifier '%s'",id->name); +} + +/* complain about a redefined identifier */ + +redef(id) +IDTYPE *id; +{ + if(chkgram) + error("redefined identifier '%s'",id->name); +} + +/* display an error */ + +error(f,s) +char *f, *s; +{ + if(newline) { + printf("\n"); + newline=0; + } + + if(file!=NULL) + fprintf(stderr,"%s, line %u: ",file,line); + + fprintf(stderr,f,s); + + if(errorid!=NULL) + fprintf(stderr," in rule '%s'",errorid->name); + + fprintf(stderr,"\n"); +} + +fatal(f,s) +char *f,*s; +{ + error(f,s); + + if(outf!=NULL) { + fclose(outf); + unlink(outfile); + } +} + -- cgit v1.2.3