87a2315037
*Important:* Do `make clean` to work around a problem and prevent infinite rebuilds, https://github.com/davidgiven/ack/issues/68 I edit tokens.g in util/LLgen/src, so I regenerate tokens.c. The regeneration script bootstrap.sh can't find LLgen, but I can run the same command by typing the path to llgen.
378 lines
8.6 KiB
C
378 lines
8.6 KiB
C
/*
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "ack.h"
|
|
#include <em_path.h>
|
|
#include "list.h"
|
|
#include "trans.h"
|
|
#include "grows.h"
|
|
#include "dmach.h"
|
|
#include "data.h"
|
|
|
|
#ifndef NORCSID
|
|
static char rcs_id[] = "$Id$" ;
|
|
static char rcs_dmach[] = RCS_DMACH ;
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* Read machine definitions and transformations */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
#define COMMENT '#'
|
|
|
|
#define VAR "var"
|
|
#define PASS "name"
|
|
#define IN "from"
|
|
#define OUT "to"
|
|
#define RES "outfile"
|
|
#define PROG "program"
|
|
#define MAPF "mapflag"
|
|
#define ARGS "args"
|
|
#define STD_IN "stdin"
|
|
#define STD_OUT "stdout"
|
|
#define PREP "prep"
|
|
#define OPT "optimizer"
|
|
#define LINKER "linker"
|
|
#define COMBINER "combiner"
|
|
#define PRIO "priority"
|
|
#define RUNT "rts"
|
|
#define NEEDT "need"
|
|
#define CALL "callname"
|
|
#define END "end"
|
|
|
|
static void intrf(void) ;
|
|
static void open_in(char *) ;
|
|
static void close_in(void) ;
|
|
static int getinchar(void) ;
|
|
static int getln(void) ;
|
|
|
|
static char *ty_name ;
|
|
static char *bol ;
|
|
static char *inname ;
|
|
|
|
void setlist(char *name) {
|
|
/* Name is sought in the internal tables,
|
|
if not present, the a file of that name is sought
|
|
in first the current and then the EM Lib directory
|
|
*/
|
|
|
|
inname=name ;
|
|
open_in(name) ;
|
|
while ( getln() ) {
|
|
if ( strcmp(VAR,ty_name)==0 ) {
|
|
doassign(bol,(char *)0,0) ;
|
|
} else
|
|
if ( strcmp(CALL,ty_name)==0 ) {
|
|
if ( callname && strcmp(bol,callname)==0 ) {
|
|
callname= (char *)0 ;
|
|
#ifdef DEBUG
|
|
if ( debug>=3 ) {
|
|
vprint("found call name\n");
|
|
}
|
|
#endif
|
|
}
|
|
} else
|
|
if ( strcmp(PASS,ty_name)==0 ) {
|
|
intrf() ;
|
|
} else
|
|
error("unknown keyword %s",ty_name) ;
|
|
}
|
|
close_in();
|
|
#ifdef DEBUG
|
|
if ( debug>=3 ) vprint("End %s\n",name) ;
|
|
#endif
|
|
}
|
|
|
|
static int inoptlist(char *nm) {
|
|
register char *p=Optlist ;
|
|
|
|
while ( p && *p ) {
|
|
register char *q=nm ;
|
|
|
|
while ( *q!='\0' && *q++==*p ) p++ ;
|
|
if ( *q=='\0' && ( *p=='\0' || *p==',' ) ) return 1 ;
|
|
while ( *p!='\0' && *p++!=',' ) /* nothing */ ;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void intrf(void) {
|
|
/* Read in trf (transformation) */
|
|
register trf *new ;
|
|
int twice ;
|
|
int name_seen=0 ;
|
|
|
|
new= (trf *)getcore(sizeof *new) ;
|
|
new->t_name= keeps(bol) ;
|
|
for (;;) {
|
|
if ( !getln() ) {
|
|
fuerror("unexpected EOF on %s",inname) ;
|
|
}
|
|
twice= NO ;
|
|
if ( strcmp(ty_name,IN)==0 ) {
|
|
if ( new->t_in ) twice=YES ;
|
|
new->t_in= keeps(bol);
|
|
} else
|
|
if ( strcmp(ty_name,OUT)==0 ) {
|
|
if ( new->t_out ) twice=YES ;
|
|
new->t_out= keeps(bol);
|
|
} else
|
|
if ( strcmp(ty_name,PROG)==0 ) {
|
|
if ( new->t_prog ) twice=YES ;
|
|
new->t_prog= keeps(bol);
|
|
} else
|
|
if ( strcmp(ty_name,MAPF)==0 ) {
|
|
l_add(&new->t_mapf,keeps(bol)) ;
|
|
} else
|
|
if ( strcmp(ty_name,ARGS)==0 ) {
|
|
if ( new->t_argd ) twice=YES ;
|
|
new->t_argd= keeps(bol) ;
|
|
} else
|
|
if ( strcmp(ty_name,STD_IN)==0 ) {
|
|
if ( new->t_stdin ) twice=YES ;
|
|
new->t_stdin= YES ;
|
|
} else
|
|
if ( strcmp(ty_name,STD_OUT)==0 ) {
|
|
if ( new->t_stdout ) twice=YES ;
|
|
new->t_stdout= YES ;
|
|
} else
|
|
if ( strcmp(ty_name,PREP)==0 ) {
|
|
if ( strcmp(bol,"always")==0 ) {
|
|
if ( new->t_prep ) twice=YES ;
|
|
new->t_prep=YES ;
|
|
} else
|
|
if ( strcmp(bol,"cond")==0 ) {
|
|
if ( new->t_prep ) twice=YES ;
|
|
new->t_prep=MAYBE ;
|
|
} else
|
|
if ( strcmp(bol,"is")==0 ) {
|
|
if ( new->t_isprep ) twice=YES ;
|
|
new->t_isprep= YES ;
|
|
} else
|
|
{
|
|
fuerror("illegal preprocessor spec in %s: %s",
|
|
inname,bol) ;
|
|
}
|
|
} else
|
|
if ( strcmp(ty_name,OPT)==0 ) {
|
|
if ( new->t_optim ) twice=YES ;
|
|
new->t_optim= atoi(bol) ;
|
|
if (new->t_optim <= 0) new->t_optim = 1;
|
|
} else
|
|
if ( strcmp(ty_name,LINKER)==0 ) {
|
|
if ( new->t_linker ) twice=YES ;
|
|
new->t_linker= YES ;
|
|
new->t_combine= YES ;
|
|
} else
|
|
if ( strcmp(ty_name,COMBINER)==0 ) {
|
|
if ( new->t_combine ) twice=YES ;
|
|
new->t_combine= YES ;
|
|
} else
|
|
if ( strcmp(ty_name,PRIO)==0 ) {
|
|
new->t_priority= atoi(bol) ;
|
|
} else
|
|
if ( strcmp(ty_name,RUNT)==0 ) {
|
|
if ( new->t_rts ) twice=YES ;
|
|
new->t_rts= keeps(bol) ;
|
|
} else
|
|
if ( strcmp(ty_name,NEEDT)==0 ) {
|
|
if ( new->t_needed ) twice=YES ;
|
|
new->t_needed= keeps(bol) ;
|
|
} else
|
|
if ( strcmp(ty_name,RES)==0 ) {
|
|
if ( new->t_outfile ) twice=YES ;
|
|
new->t_outfile= keeps(bol) ;
|
|
} else
|
|
if ( strcmp(ty_name,CALL)==0 ) {
|
|
if ( callname && strcmp(bol,callname)==0 ) {
|
|
name_seen=1 ;
|
|
callname= (char *)0 ;
|
|
#ifdef DEBUG
|
|
if ( debug>=3 ) {
|
|
vprint("found call name in %s\n",
|
|
new->t_name) ;
|
|
}
|
|
#endif
|
|
}
|
|
} else
|
|
if ( strcmp(ty_name,END)==0 ) {
|
|
break ;
|
|
} else {
|
|
fuerror("illegal keyword %s %s",ty_name,bol);
|
|
}
|
|
if ( twice ) {
|
|
werror("%s: specified twice for %s",
|
|
ty_name, new->t_name) ;
|
|
}
|
|
}
|
|
if ( ! ( new->t_name && new->t_out && new->t_prog ) ) {
|
|
fuerror("insufficient specification for %s in %s",
|
|
new->t_name,inname) ;
|
|
}
|
|
if ( ! new->t_argd ) new->t_argd="" ;
|
|
/* Warning, side effect */
|
|
if ( name_seen && new->t_rts ) {
|
|
if ( rts && strcmp(rts,new->t_rts)!=0 ) {
|
|
error("Attempt to use two run-time systems, %s and %s",
|
|
rts, new->t_rts) ;
|
|
}
|
|
rts= new->t_rts ;
|
|
l_add(&head_list, rts) ;
|
|
l_add(&tail_list, rts) ;
|
|
}
|
|
#ifdef DEBUG
|
|
if ( debug>=3 ) {
|
|
register list_elem *elem ;
|
|
vprint("%s: from %s to %s '%s'\n",
|
|
new->t_name,new->t_in ? new->t_in : "(null)",new->t_out,new->t_prog) ;
|
|
vprint("\targs: %s",new->t_argd) ;
|
|
scanlist( l_first(new->t_mapf), elem ) {
|
|
vprint("\t%s\n",l_content(*elem)) ;
|
|
}
|
|
if ( new->t_rts ) vprint("\trts: %s\n",new->t_rts) ;
|
|
if ( new->t_needed ) vprint("\tneeded: %s\n",new->t_needed) ;
|
|
}
|
|
#endif
|
|
if ( new->t_optim &&
|
|
( new->t_optim <= Optlevel || inoptlist(new->t_name) ) ) {
|
|
new->t_optim = Optlevel;
|
|
}
|
|
l_add(&tr_list,(char *)new) ;
|
|
}
|
|
|
|
/************************** IO from core or file *******************/
|
|
|
|
static int incore ;
|
|
static growstring rline ;
|
|
static FILE *infile ;
|
|
static char *inptr ;
|
|
char *em_dir = EM_DIR;
|
|
|
|
static void open_in(char *name) {
|
|
register dmach *cmac ;
|
|
|
|
gr_init(&rline) ;
|
|
for ( cmac= massoc ; cmac->ma_index!= -1 ; cmac++ ) {
|
|
if ( strcmp(name,cmac->ma_name)==0 ) {
|
|
incore=YES ;
|
|
inptr= &intable[cmac->ma_index] ;
|
|
return ;
|
|
}
|
|
}
|
|
/* Not in core */
|
|
incore= NO ;
|
|
/* Try to read EM_DIR/lib/MACH/descr */
|
|
gr_cat(&rline,em_dir) ;
|
|
gr_cat(&rline,"/lib/") ; gr_cat(&rline,name) ;
|
|
gr_cat(&rline,"/descr") ;
|
|
infile= fopen(gr_start(rline),"r") ;
|
|
if ( !infile ) {
|
|
gr_throw(&rline) ;
|
|
gr_cat(&rline,em_dir) ; gr_cat(&rline,"/") ;
|
|
gr_cat(&rline,ACK_PATH); gr_cat(&rline,"/") ;
|
|
gr_cat(&rline,name) ;
|
|
infile= fopen(gr_start(rline),"r") ;
|
|
}
|
|
if ( !infile ) {
|
|
infile= fopen(name,"r") ;
|
|
}
|
|
if ( infile==NULL ) {
|
|
fuerror("Cannot find description for %s",name) ;
|
|
}
|
|
}
|
|
|
|
static void close_in(void) {
|
|
if ( !incore ) fclose(infile) ;
|
|
gr_throw(&rline) ;
|
|
}
|
|
|
|
static char *readline(void) {
|
|
/* Get a line from the input,
|
|
return 0 if at end,
|
|
The line is stored in a volatile buffer,
|
|
a pointer to the line is returned.
|
|
*/
|
|
register int nchar ;
|
|
enum { BOL, ESCAPE, SKIPPING, MOL } state = BOL ;
|
|
|
|
gr_throw(&rline) ;
|
|
for (;;) {
|
|
nchar= getinchar() ;
|
|
if ( nchar==EOF ) {
|
|
if ( state!=BOL ) {
|
|
werror("incomplete line in %s", inname) ;
|
|
}
|
|
return 0 ;
|
|
}
|
|
if ( state==SKIPPING ) {
|
|
if ( nchar=='\n' ) {
|
|
state= MOL ;
|
|
} else {
|
|
continue ;
|
|
}
|
|
}
|
|
if ( state==ESCAPE ) {
|
|
switch( nchar ) {
|
|
case '\n' :
|
|
break ;
|
|
default :
|
|
gr_add(&rline,BSLASH) ;
|
|
case COMMENT :
|
|
case BSLASH :
|
|
gr_add(&rline,nchar) ;
|
|
break ;
|
|
}
|
|
state= MOL ;
|
|
continue ;
|
|
}
|
|
switch ( nchar ) {
|
|
case '\n' : gr_add(&rline,0) ;
|
|
return gr_start(rline) ;
|
|
case COMMENT : state= SKIPPING ;
|
|
break ;
|
|
case BSLASH : state= ESCAPE ;
|
|
break ;
|
|
default : gr_add(&rline,nchar) ;
|
|
state= MOL ;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int getinchar(void) {
|
|
register int token ;
|
|
|
|
if ( incore ) {
|
|
if ( *inptr==0 ) return EOF ;
|
|
return *inptr++ ;
|
|
}
|
|
token= getc(infile) ;
|
|
if ( (token>=0177 || token <=0 ) && token !=EOF ) {
|
|
fuerror("Non-ascii character in description file %s",inname);
|
|
}
|
|
return token ;
|
|
}
|
|
|
|
static int getln(void) {
|
|
register char *c_ptr ;
|
|
|
|
do {
|
|
if ( (c_ptr=readline())==(char *)0 ) return 0 ;
|
|
ty_name= skipblank(c_ptr) ;
|
|
} while ( *ty_name==0 ) ;
|
|
c_ptr= firstblank(ty_name) ;
|
|
if ( *c_ptr ) {
|
|
*c_ptr++ =0 ;
|
|
c_ptr= skipblank(c_ptr) ;
|
|
}
|
|
bol= c_ptr ;
|
|
return 1 ;
|
|
}
|