mawk0.97.shar 3 of 6
Mike Brennan
brennan at ssc-vax.UUCP
Sun May 12 00:52:40 AEST 1991
------------------cut here----------------
register FCALL_REC *q = &dummy ; /* trails p */
q->link = p ;
while ( p )
{
if ( ! p->callee->code )
{ /* callee never defined */
errmsg(0, "line %u: function %s never defined" ,
p->line_no, p->callee->name) ;
if ( ++compile_error_count == MAX_COMPILE_ERRORS )
mawk_exit(1) ;
/* delete p from list */
q->link = p->link ;
/* don't worry about freeing memory, we'll exit soon */
}
else /* note p->arg_list starts with last argument */
if ( ! p->arg_list /* nothing to do */ ||
! p->arg_cnt_checked &&
! arg_cnt_ok(p->callee, p->arg_list, p->line_no) )
{ q->link = p->link ; /* delete p */
/* the ! arg_list case is not an error so free memory */
zfree(p, sizeof(FCALL_REC)) ;
}
else
{ /* keep p and set call_start */
q = p ;
switch ( p->call_scope )
{
case SCOPE_MAIN :
p->call_start = main_start ;
break ;
case SCOPE_BEGIN :
p->call_start = begin_start ;
break ;
case SCOPE_END :
p->call_start = end_start ;
break ;
case SCOPE_FUNCT :
p->call_start = p->call->code ;
break ;
}
}
p = q->link ;
}
return dummy.link ;
}
/* continuously walk the resolve_list making type deductions
until this list goes empty or no more progress can be made
(An example where no more progress can be made is at end of file
*/
void resolve_fcalls()
{ register FCALL_REC *p, *old_list , *new_list ;
int progress ; /* a flag */
old_list = first_pass(resolve_list) ;
new_list = (FCALL_REC *) 0 ;
progress = 0 ;
while ( 1 )
{
if ( !(p = old_list) )
{ /* flop the lists */
if ( !(p = old_list = new_list) /* nothing left */
|| ! progress /* can't do any more */ ) return ;
/* reset after flop */
new_list = (FCALL_REC *) 0 ; progress = 0 ;
}
old_list = p->link ;
if ( p->arg_list = call_arg_check(p->callee, p->arg_list ,
p->call_start, p->line_no) )
{
/* still have work to do , put on new_list */
progress |= check_progress ;
p->link = new_list ; new_list = p ;
}
else /* done with p */
{ progress = 1 ; zfree(p, sizeof(FCALL_REC)) ; }
}
}
/* the parser has just reduced a function call ;
the info needed to type check is passed in. If type checking
can not be done yet (most common reason -- function referenced
but not defined), a node is added to the resolve list.
*/
void check_fcall( callee, call_scope, call, arg_list, line_no )
FBLOCK *callee ;
int call_scope ;
FBLOCK *call ;
CA_REC *arg_list ;
unsigned line_no ;
{
FCALL_REC *p ;
INST *call_start ;
if ( ! callee->code )
{ /* forward reference to a function to be defined later */
p = (FCALL_REC *) zmalloc(sizeof(FCALL_REC)) ;
p->callee = callee ;
p->call_scope = call_scope ;
p->call = call ;
p->arg_list = arg_list ;
p->arg_cnt_checked = 0 ;
p->line_no = line_no ;
/* add to resolve list */
p->link = resolve_list ; resolve_list = p ;
}
else
if ( arg_list && arg_cnt_ok( callee, arg_list, line_no ) )
{
switch ( call_scope )
{
case SCOPE_MAIN :
call_start = main_start ;
break ;
case SCOPE_BEGIN :
call_start = begin_start ;
break ;
case SCOPE_END :
call_start = end_start ;
break ;
case SCOPE_FUNCT :
call_start = call->code ;
break ;
}
/* usually arg_list disappears here and all is well
otherwise add to resolve list */
if ( arg_list = call_arg_check(callee, arg_list,
call_start, line_no) )
{
p = (FCALL_REC *) zmalloc(sizeof(FCALL_REC)) ;
p->callee = callee ;
p->call_scope = call_scope ;
p->call = call ;
p->arg_list = arg_list ;
p->arg_cnt_checked = 1 ;
p->line_no = line_no ;
/* add to resolve list */
p->link = resolve_list ; resolve_list = p ;
}
}
}
/* example where typing cannot progress
{ f(z) }
function f(x) { print NR }
# this is legal, does something useful, but absurdly written
# We have to design so this works
*/
@//E*O*F mawk0.97/fcall.c//
chmod u=rw,g=r,o=r mawk0.97/fcall.c
echo x - mawk0.97/field.c
sed 's/^@//' > "mawk0.97/field.c" <<'@//E*O*F mawk0.97/field.c//'
/********************************************
field.c
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the Awk programming language as defined in
Aho, Kernighan and Weinberger, The AWK Programming Language,
Addison-Wesley, 1988.
See the accompaning file, LIMITATIONS, for restrictions
regarding modification and redistribution of this
program in source or binary form.
********************************************/
/* $Log: field.c,v $
* Revision 2.2 91/04/09 12:39:00 brennan
* added static to funct decls to satisfy STARDENT compiler
*
* Revision 2.1 91/04/08 08:23:01 brennan
* VERSION 0.97
*
*/
/* field.c */
#include "mawk.h"
#include "field.h"
#include "init.h"
#include "memory.h"
#include "scan.h"
#include "bi_vars.h"
#include "repl.h"
#include "regexp.h"
CELL field[NUM_FIELDS] ;
/* statics */
static void PROTO( build_field0, (void) ) ;
static void PROTO( xcast, (CELL *) ) ;
static void PROTO( set_rs_shadow, (void) ) ;
/* the order is important here, must be the same as
postion after field[MAX_FIELD] */
static char *biv_field_names[] = {
"NF" , "RS" , "FS", "OFMT" } ;
/* a description of how to split based on RS.
If RS is changed, so is rs_shadow */
SEPARATOR rs_shadow = {SEP_CHAR, '\n'} ;
/* a splitting CELL version of FS */
CELL fs_shadow = {C_SPACE} ;
int nf ;
/* nf holds the true value of NF. If nf < 0 , then
NF has not been computed, i.e., $0 has not been split
*/
static void set_rs_shadow()
{ CELL c ;
STRING *sval ;
char *s ;
unsigned len ;
if ( rs_shadow.type == SEP_STR ) free_STRING((STRING*) rs_shadow.ptr) ;
cast_for_split( cellcpy(&c, field+RS) ) ;
switch( c.type )
{
case C_RE :
if ( s = is_string_split(c.ptr, &len) )
if ( len == 1 )
{ rs_shadow.type = SEP_CHAR ;
rs_shadow.c = s[0] ;
}
else
{ rs_shadow.type = SEP_STR ;
rs_shadow.ptr = (PTR) new_STRING(s) ;
}
else
{ rs_shadow.type = SEP_RE ;
rs_shadow.ptr = c.ptr ;
}
break ;
case C_SPACE :
rs_shadow.type = SEP_CHAR ;
rs_shadow.c = ' ' ;
break ;
case C_SNULL : /* RS becomes one or more blank lines */
rs_shadow.type = SEP_RE ;
sval = new_STRING( "\n([ \t]*\n)+" ) ;
rs_shadow.ptr = re_compile(sval) ;
free_STRING(sval) ;
break ;
default : bozo("bad cell in set_rs_shadow") ;
}
}
void field_init()
{ char **p = biv_field_names ;
SYMTAB *st_p ;
int i ;
for(i = NF ; i < NUM_FIELDS ; p++ , i++ )
{
st_p = insert( *p ) ;
st_p->type = ST_FIELD ;
st_p->stval.cp = &field[i] ;
}
field[NF].type = C_DOUBLE ;
field[NF].dval = 0.0 ;
field[0].type = C_STRING ;
field[0].ptr = (PTR) & null_str ;
null_str.ref_cnt++ ;
field[RS].type = C_STRING ;
field[RS].ptr = (PTR) new_STRING( "\n" ) ;
/* rs_shadow already set */
field[FS].type = C_STRING ;
field[FS].ptr = (PTR) new_STRING( " " ) ;
/* fs_shadow is already set */
field[OFMT].type = C_STRING ;
field[OFMT].ptr = (PTR) new_STRING( "%.6g" ) ;
}
void set_field0( s, len)
char *s ;
unsigned len ;
{
cell_destroy( & field[0] ) ;
nf = -1 ;
if ( len )
{
field[0].type = C_MBSTRN ;
field[0].ptr = (PTR) new_STRING( (char *) 0, len) ;
(void) memcpy( string(&field[0])->str, s, len ) ;
}
else
{
field[0].type = C_STRING ;
field[0].ptr = (PTR) &null_str ;
null_str.ref_cnt++ ;
}
}
/* split field[0] into $1, $2 ... and set NF */
void split_field0()
{ register int i ;
CELL c ;
int cast_flag ; /* we had to cast field[0] */
char *s ;
unsigned len ;
if ( fs_shadow.type == C_SNULL ) /* FS == "" */
{ cell_destroy(field+1) ;
(void) cellcpy(field+1, field+0) ;
cell_destroy(field+NF) ;
field[NF].type = C_DOUBLE ; field[NF].dval = 1.0 ;
return ;
}
if ( field[0].type < C_STRING )
{ cast1_to_s(cellcpy(&c, field+0)) ;
s = string(&c)->str ;
len = string(&c)->len ;
cast_flag = 1 ;
}
else
{ s = string(field)->str ;
len = string(field)->len ;
cast_flag = 0 ;
}
nf = len == 0 ? 0 :
fs_shadow.type == C_SPACE
? space_split(s) : re_split(s, fs_shadow.ptr) ;
cell_destroy(field+NF) ;
field[NF].type = C_DOUBLE ;
field[NF].dval = (double) nf ;
for( i = 1 ; i <= nf ; i++ )
{
cell_destroy(field+i) ;
field[i].ptr = temp_buff.ptr_buff[i-1] ;
field[i].type = C_MBSTRN ;
}
if ( cast_flag ) free_STRING( string(&c) ) ;
}
/*
assign CELL *cp to field[i]
and take care of all side effects
*/
void field_assign( i, cp)
register int i ;
CELL *cp ;
{ register int j ;
CELL c ;
/* update fields not up to date */
if ( nf < 0 ) split_field0() ;
switch( i )
{
case 0 :
cell_destroy(field) ;
nf = -1 ;
(void) cellcpy(field, cp) ;
break ; ;
case NF :
cell_destroy(field+NF) ;
(void) cellcpy(field+NF, cellcpy(&c,cp) ) ;
if ( c.type != C_DOUBLE ) cast1_to_d(&c) ;
if ( (j = (int) c.dval) < 0 )
rt_error("negative value assigned to NF") ;
if ( j > MAX_FIELD )
rt_overflow("MAX_FIELD", MAX_FIELD) ;
if ( j > nf )
for ( i = nf+1 ; i <= j ; i++ )
{ cell_destroy(field+i) ;
field[i].type = C_STRING ;
field[i].ptr = (PTR) &null_str ;
null_str.ref_cnt++ ;
}
nf = j ;
build_field0() ;
break ;
case RS :
cell_destroy(field+RS) ;
(void) cellcpy(field+RS, cp) ;
set_rs_shadow() ;
break ;
case FS :
cell_destroy(field+FS) ;
cast_for_split( cellcpy(&fs_shadow, cellcpy(field+FS, cp)) ) ;
break ;
case OFMT :
/* If the user does something stupid with OFMT, we could crash.
We'll make an attempt to protect ourselves here. This is
why OFMT is made a field.
The ptr of OFMT always has a valid STRING, even if assigned
a DOUBLE or NOINIT
*/
free_STRING( string(field+OFMT) ) ;
(void) cellcpy(field+OFMT, cp) ;
if ( field[OFMT].type < C_STRING ) /* !! */
field[OFMT].ptr = (PTR) new_STRING( "%.6g" ) ;
else
{
/* It's a string, but if it's really goofy it could still
damage us. Test it . */
temp_buff.string_buff[256] = 0 ;
(void) sprintf(temp_buff.string_buff,
string(field+OFMT)->str, 3.1459) ;
if ( temp_buff.string_buff[256] )
rt_error("OFMT assigned unusable value") ;
}
break ;
default:
#ifdef DEBUG
if ( i < 0 )
bozo("negative field index in field_assign") ;
if ( i > MAX_FIELD )
bozo("large field index in field_assign") ;
#endif
cell_destroy(field+i) ;
(void) cellcpy(field+i, cp) ;
if ( i > nf )
{ for ( j = nf+1 ; j < i ; j++ )
{ cell_destroy(field+j) ;
field[j].type = C_STRING ;
field[j].ptr = (PTR) &null_str ;
null_str.ref_cnt++ ;
}
nf = i ;
cell_destroy(field+NF) ;
field[NF].type = C_DOUBLE ;
field[NF].dval = (double) i ;
}
build_field0() ;
}
}
/* get the string rep of a double without changing its
type */
static void xcast( cp )
register CELL *cp ;
{
switch ( cp->type )
{
case C_NOINIT :
cp->ptr = (PTR) &null_str ;
null_str.ref_cnt++ ;
break ;
case C_DOUBLE :
(void) sprintf(temp_buff.string_buff,
string(field+OFMT)->str, cp->dval) ;
cp->ptr = (PTR) new_STRING(temp_buff.string_buff) ;
break ;
}
}
/* construct field[0] from the other fields */
static void build_field0()
{
#ifdef DEBUG
if ( nf < 0 )
bozo("nf <0 in build_field0") ;
#endif
cell_destroy( field+0 ) ;
if ( nf == 0 )
{ field[0].type = C_STRING ;
field[0].ptr = (PTR) &null_str ;
null_str.ref_cnt++ ;
}
else
if ( nf == 1 ) (void) cellcpy(field, field+1) ;
else
{ CELL ofs ;
char *ofs_str ;
unsigned ofs_len , len0 = 0 ;
register int i ;
register char *p, *q ;
(void) cellcpy(& ofs , bi_vars + OFS) ;
if ( ofs.type < C_STRING ) cast1_to_s(&ofs) ;
ofs_str = string(&ofs)->str ;
ofs_len = string(&ofs)->len ;
for( i = 1 ; i <= nf ; i++ )
{
if ( field[i].type < C_STRING ) xcast(field+i) ;
len0 += string(field+i)->len + ofs_len ;
}
len0 -= ofs_len ;
field[0].type = C_STRING ;
field[0].ptr = (PTR) new_STRING((char *) 0, len0) ;
p = string(field)->str ;
for( i = 1 ; i < nf ; i++ )
{
(void) memcpy(p, string(field+i)->str, string(field+i)->len) ;
p += string(field+i)->len ;
/* add the separator */
q = ofs_str ;
while ( *p++ = *q++ ) ; p-- ;
/* if not really string undo the xcast */
if ( field[i].type < C_STRING )
free_STRING( string(field+i) ) ;
}
/* do the last piece */
(void) memcpy(p, string(field+i)->str, string(field+i)->len) ;
if ( field[i].type < C_STRING )
free_STRING( string(field+i) ) ;
free_STRING( string(&ofs) ) ;
}
}
@//E*O*F mawk0.97/field.c//
chmod u=rw,g=r,o=r mawk0.97/field.c
echo x - mawk0.97/field.h
sed 's/^@//' > "mawk0.97/field.h" <<'@//E*O*F mawk0.97/field.h//'
/********************************************
field.h
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the Awk programming language as defined in
Aho, Kernighan and Weinberger, The AWK Programming Language,
Addison-Wesley, 1988.
See the accompaning file, LIMITATIONS, for restrictions
regarding modification and redistribution of this
program in source or binary form.
********************************************/
/* $Log: field.h,v $
* Revision 2.1 91/04/08 08:23:03 brennan
* VERSION 0.97
*
*/
/* field.h */
#ifndef FIELD_H
#define FIELD_H 1
void PROTO( set_field0, (char *, unsigned) ) ;
void PROTO( split_field0, (void) ) ;
int PROTO( is_strnum, (char *, unsigned, double *) ) ;
void PROTO( field_assign, (int, CELL *) ) ;
char *PROTO( is_string_split, (PTR , unsigned *) ) ;
#define NF (MAX_FIELD+1)
#define RS (MAX_FIELD+2)
#define FS (MAX_FIELD+3)
#define OFMT (MAX_FIELD+4)
#define NUM_FIELDS (MAX_FIELD+5)
extern CELL field[NUM_FIELDS] ;
extern int nf ; /* shadows NF */
/* a shadow type for RS and FS */
#define SEP_SPACE 0
#define SEP_CHAR 1
#define SEP_STR 2
#define SEP_RE 3
typedef struct {
char type ;
char c ;
PTR ptr ; /* STRING* or RE machine* */
} SEPARATOR ;
extern SEPARATOR rs_shadow ;
extern CELL fs_shadow ;
#endif /* FIELD_H */
@//E*O*F mawk0.97/field.h//
chmod u=rw,g=r,o=r mawk0.97/field.h
echo x - mawk0.97/files.c
sed 's/^@//' > "mawk0.97/files.c" <<'@//E*O*F mawk0.97/files.c//'
/********************************************
files.c
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the Awk programming language as defined in
Aho, Kernighan and Weinberger, The AWK Programming Language,
Addison-Wesley, 1988.
See the accompaning file, LIMITATIONS, for restrictions
regarding modification and redistribution of this
program in source or binary form.
********************************************/
/*$Log: files.c,v $
* Revision 2.1 91/04/08 08:23:05 brennan
* VERSION 0.97
*
*/
/* files.c */
#include "mawk.h"
#include "files.h"
#include "memory.h"
#include <stdio.h>
#include "fin.h"
#if ! DOS
#include <fcntl.h>
#endif
/* We store dynamically created files on a linked linear
list with move to the front (big surprise) */
typedef struct file {
struct file *link ;
STRING *name ;
short type ;
#if ! DOS
int pid ; /* we need to wait() when we close an out pipe */
#endif
PTR ptr ; /* FIN* or FILE* */
} FILE_NODE ;
static FILE_NODE *file_list ;
PTR file_find( sval, type )
STRING *sval ;
int type ;
{ register FILE_NODE *p = file_list ;
FILE_NODE *q = (FILE_NODE *) 0 ;
char *name = sval->str ;
while (1)
{
if ( !p ) /* open a new one */
{
p = (FILE_NODE*) zmalloc(sizeof(FILE_NODE)) ;
switch( p->type = type )
{
case F_TRUNC :
if ( !(p->ptr = (PTR) fopen(name, "w")) )
goto out_failure ;
break ;
case F_APPEND :
if ( !(p->ptr = (PTR) fopen(name, "a")) )
goto out_failure ;
break ;
case F_IN :
if ( !(p->ptr = (PTR) FINopen(name, 0)) )
{ zfree(p, sizeof(FILE_NODE)) ; return (PTR) 0 ; }
break ;
case PIPE_OUT :
case PIPE_IN :
#if DOS
rt_error("pipes not supported under MsDOS") ;
#else
if ( !(p->ptr = get_pipe(name, type, &p->pid)) )
if ( type == PIPE_OUT ) goto out_failure ;
else
{ zfree(p, sizeof(FILE_NODE) ) ;
return (PTR) 0 ;
}
#endif
break ;
#ifdef DEBUG
default :
bozo("bad file type") ;
#endif
}
/* successful open */
p->name = sval ;
sval->ref_cnt++ ;
break ;
}
if ( strcmp(name, p->name->str) == 0 )
{
if ( p->type != type ) goto type_failure ;
if ( !q ) /*at front of list */
return p->ptr ;
/* delete from list for move to front */
q->link = p->link ;
break ;
}
q = p ; p = p->link ;
}
/* put p at the front of the list */
p->link = file_list ;
return (PTR) (file_list = p)->ptr ;
out_failure:
errmsg(errno, "cannot open \"%s\" for output", name) ;
mawk_exit(1) ;
type_failure :
rt_error("use of file \"%s\"\n\tis inconsistent with previous use",
name) ;
}
/* close a file and delete it's node from the file_list */
int file_close( sval )
STRING *sval ;
{ register FILE_NODE *p = file_list ;
FILE_NODE *q = (FILE_NODE *) 0 ; /* trails p */
char *name = sval->str ;
while ( p )
if ( strcmp(name,p->name->str) == 0 ) /* found */
{
switch( p->type )
{
case F_TRUNC :
case F_APPEND :
(void) fclose((FILE *) p->ptr) ;
break ;
case PIPE_OUT :
(void) fclose((FILE *) p->ptr) ;
#if ! DOS
(void) wait_for(p->pid) ;
#endif
break ;
case F_IN :
case PIPE_IN :
FINclose((FIN *) p->ptr) ;
break ;
}
free_STRING(p->name) ;
if ( q ) q->link = p->link ;
else file_list = p->link ;
zfree(p, sizeof(FILE_NODE)) ;
return 0 ;
}
else { q = p ; p = p->link ; }
/* its not on the list */
return -1 ;
}
/* When we exit, we need to close and wait for all output pipes */
#if !DOS
void close_out_pipes()
{ register FILE_NODE *p = file_list ;
while ( p )
{ if ( p->type == PIPE_OUT )
{ (void) fclose((FILE *) p->ptr) ; (void) wait_for(p->pid) ; }
p = p->link ;
}
}
#endif
char *shell ;
#if ! DOS
PTR get_pipe( name, type, pid_ptr)
char *name ;
int type ;
int *pid_ptr ;
{ int the_pipe[2], local_fd, remote_fd ;
if ( ! shell ) shell = (shell = getenv("SHELL")) ? shell :"/bin/sh" ;
if ( pipe(the_pipe) == -1 ) return (PTR) 0 ;
local_fd = the_pipe[type == PIPE_OUT] ;
remote_fd = the_pipe[type == PIPE_IN ] ;
switch( *pid_ptr = fork() )
{ case -1 :
(void) close(local_fd) ;
(void) close(remote_fd) ;
return (PTR) 0 ;
case 0 :
(void) close(local_fd) ;
(void) close(type == PIPE_IN) ;
(void) dup( remote_fd ) ;
(void) close( remote_fd ) ;
(void) execl(shell, shell, "-c", name, (char *) 0 ) ;
errmsg(errno, "failed to exec %s -c %s" , shell, name) ;
fflush(stderr) ;
_exit(128) ;
default :
(void) close(remote_fd) ;
/* we could deadlock if future child inherit the local fd ,
set close on exec flag */
(void) fcntl(local_fd, F_SETFD, 1) ;
break ;
}
return type == PIPE_IN ? (PTR) FINdopen(local_fd, 0) :
(PTR) fdopen(local_fd, "w") ;
}
/*------------ children ------------------*/
/* we need to wait for children at the end of output pipes to
complete so we know any files they have created are complete */
/* dead children are kept on this list */
static struct child {
int pid ;
int exit_status ;
struct child *link ;
} *child_list ;
static void add_to_child_list(pid, exit_status)
int pid, exit_status ;
{ register struct child *p =
(struct child *) zmalloc(sizeof(struct child)) ;
p->pid = pid ; p->exit_status = exit_status ;
p->link = child_list ; child_list = p ;
}
static struct child *remove_from_child_list(pid)
int pid ;
{ register struct child *p = child_list ;
struct child *q = (struct child *) 0 ;
while ( p )
if ( p->pid == pid )
{
if ( q ) q->link = p->link ;
else child_list = p->link ;
break ;
}
else { q = p ; p = p->link ; }
return p ; /* null return if not in the list */
}
/* wait for a specific child to complete and return its
exit status */
int wait_for(pid)
int pid ;
{ int exit_status ;
struct child *p ;
int id ;
/* see if an earlier wait() caught our child */
if ( p = remove_from_child_list(pid) )
{ exit_status = p->exit_status ;
zfree(p, sizeof(struct child)) ;
}
else /* need to really wait */
while ( (id = wait(&exit_status)) != pid )
if ( id == -1 ) /* can't happen */ bozo("wait_for") ;
else
{ /* we got the exit status of another child
put it on the child list and try again */
add_to_child_list(id, exit_status ) ;
}
return exit_status ;
}
#endif
@//E*O*F mawk0.97/files.c//
chmod u=rw,g=r,o=r mawk0.97/files.c
echo x - mawk0.97/files.h
sed 's/^@//' > "mawk0.97/files.h" <<'@//E*O*F mawk0.97/files.h//'
/********************************************
files.h
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the Awk programming language as defined in
Aho, Kernighan and Weinberger, The AWK Programming Language,
Addison-Wesley, 1988.
See the accompaning file, LIMITATIONS, for restrictions
regarding modification and redistribution of this
program in source or binary form.
********************************************/
/*$Log: files.h,v $
* Revision 2.1 91/04/08 08:23:07 brennan
* VERSION 0.97
*
*/
#ifndef FILES_H
#define FILES_H
/* IO redirection types */
#define F_IN (-5)
#define PIPE_IN (-4)
#define PIPE_OUT (-3)
#define F_APPEND (-2)
#define F_TRUNC (-1)
extern char *shell ; /* for pipes and system() */
PTR PROTO(file_find, (STRING *, int)) ;
int PROTO(file_close, (STRING *)) ;
PTR PROTO(get_pipe, (char *, int) ) ;
int PROTO(wait_for, (int) ) ;
void PROTO( close_out_pipes, (void) ) ;
#endif
@//E*O*F mawk0.97/files.h//
chmod u=rw,g=r,o=r mawk0.97/files.h
echo x - mawk0.97/fin.c
sed 's/^@//' > "mawk0.97/fin.c" <<'@//E*O*F mawk0.97/fin.c//'
/********************************************
fin.c
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the Awk programming language as defined in
Aho, Kernighan and Weinberger, The AWK Programming Language,
Addison-Wesley, 1988.
See the accompaning file, LIMITATIONS, for restrictions
regarding modification and redistribution of this
program in source or binary form.
********************************************/
/*$Log: fin.c,v $
* Revision 2.1 91/04/08 08:23:09 brennan
* VERSION 0.97
*
*/
/* fin.c */
#include "mawk.h"
#include "fin.h"
#include "memory.h"
#include "bi_vars.h"
#include "field.h"
#include "symtype.h"
#include "scan.h"
#include <fcntl.h>
extern int errno ;
int PROTO(isatty, (int) ) ;
FILE *PROTO(fdopen, (int, char*) ) ;
/* statics */
int PROTO( next_main, (void) ) ;
int PROTO( is_cmdline_assign, (char *) ) ;
FIN *FINdopen( fd, main_flag )
int fd , main_flag ;
{ register FIN *fin = (FIN *) zmalloc( sizeof(FIN) ) ;
fin->fd = fd ;
if ( main_flag )
{ fin->flags = MAIN_FLAG ;
fin->buffp = fin->buff = main_buff ;
}
else
{
fin->flags = 0 ;
fin->buffp = fin->buff = (char *) zmalloc(BUFFSZ+1) ;
}
*fin->buffp = 0 ;
if ( isatty(fd) && rs_shadow.type == SEP_CHAR
&& rs_shadow.c == '\n' )
{
/* interactive, i.e., line buffer this file */
if ( fd == 0 ) fin->fp = stdin ;
else
if ( !(fin->fp = fdopen(fd, "r")) )
{ errmsg(errno, "fdopen failed") ; exit(1) ; }
}
else fin->fp = (FILE *) 0 ;
return fin ;
}
FIN *FINopen( filename, main_flag )
char *filename ;
int main_flag ;
{ int fd ;
if ( (fd = open( filename , O_RDONLY, 0 )) == -1 )
{ errmsg( errno, "cannot open %s" , filename ) ;
return (FIN *) 0 ; }
else return FINdopen( fd, main_flag ) ;
}
void FINclose( fin )
register FIN *fin ;
{
if ( ! (fin->flags & MAIN_FLAG) )
zfree(fin->buff, BUFFSZ+1) ;
if ( fin->fd )
if ( fin->fp ) (void) fclose(fin->fp) ;
else (void) close(fin->fd) ;
zfree( fin , sizeof(FIN) ) ;
}
/* return one input record as determined by RS,
from input file (FIN) fin
*/
char *FINgets( fin, len_p )
FIN *fin ;
unsigned *len_p ;
{ register char *p, *q ;
unsigned match_len ;
unsigned r ;
restart :
if ( ! (p = fin->buffp)[0] ) /* need a refill */
{
if ( fin->flags & EOF_FLAG )
if ( (fin->flags & MAIN_FLAG) && next_main() ) goto restart ;
else
{ *len_p = 0 ; return (char *) 0 ; }
if ( fin->fp ) /* line buffering */
if ( ! fgets(fin->buff, BUFFSZ+1, fin->fp) )
{
fin->flags |= EOF_FLAG ;
fin->buff[0] = 0 ;
fin->buffp = fin->buff ;
goto restart ; /* might be main_fin */
}
else /* return this line */
{
if ( !(p = strchr(fin->buff, '\n')) )
p = fin->buff + BUFFSZ + 1 ; /* unlikely to occur */
*p = 0 ; *len_p = p - fin->buff ;
fin->buffp = p ;
return fin->buff ;
}
else /* block buffering */
{
if ( (r = fillbuff(fin->fd, fin->buff, BUFFSZ)) == 0 )
{
fin->flags |= EOF_FLAG ;
fin->buffp = fin->buff ;
goto restart ; /* might be main */
}
else
if ( r < BUFFSZ ) fin->flags |= EOF_FLAG ;
p = fin->buffp = fin->buff ;
}
}
retry:
switch( rs_shadow.type )
{
case SEP_CHAR :
q = strchr(p, rs_shadow.c) ;
match_len = 1 ;
break ;
case SEP_STR :
q = str_str(p, ((STRING *) rs_shadow.ptr)->str,
match_len = ((STRING *) rs_shadow.ptr)->len ) ;
break ;
case SEP_RE :
q = re_pos_match(p, rs_shadow.ptr, &match_len) ;
/* if the match is at the end, there might be more
still to be read */
if ( q && q[match_len] == 0 &&
p != fin->buff ) q = (char *) 0 ;
break ;
default :
bozo("type of rs_shadow") ;
}
if ( q )
{ /* the easy and normal case */
*q = 0 ; *len_p = q - p ;
fin->buffp = q + match_len ;
return p ;
}
if ( p == fin->buff ) /* last line or one huge (truncated) line */
{ *len_p = r = strlen(p) ; fin->buffp = p + r ;
/* treat truncated case as overflow */
if ( r == BUFFSZ )
{ /* overflow, update NR and FNR */
cast2_to_d(bi_vars+NR) ;
bi_vars[NR].dval += 1.0 ;
bi_vars[FNR].dval += 1.0 ;
rt_overflow("maximum record length" , BUFFSZ) ;
}
return p ;
}
/* move a partial line to front of buffer and try again */
p = (char *) memcpy( fin->buff, p, r = strlen(p) ) ;
q = p+r ;
if ( fin->flags & EOF_FLAG ) *q = 0 ;
else
{ unsigned rr = BUFFSZ - r ;
if ( (r = fillbuff(fin->fd, q, rr)) < rr ) fin->flags |= EOF_FLAG ;
}
goto retry ;
}
/*--------
target is big enough to hold size + 1 chars
on exit the back of the target is zero terminated
*--------------*/
unsigned fillbuff(fd, target, size)
int fd ;
register char *target ;
unsigned size ;
{ register int r ;
unsigned entry_size = size ;
while ( size )
switch( r = read(fd, target, size) )
{ case -1 :
errmsg(errno, "read error on file") ;
exit(1) ;
case 0 :
goto out ;
default :
target += r ; size -= r ;
break ;
}
out :
*target = 0 ;
return entry_size - size ;
}
/* main_fin is a handle to the main input stream
== -1 if never tried to open
== 0 if end of stream
otherwise active */
FIN *main_fin = (FIN *) -1 ;
ARRAY Argv ; /* to the user this is ARGV */
static int argi = 1 ; /* index of next ARGV[argi] to try to open */
int open_main() /* boolean return, true if main is open */
{
if ( bi_vars[ARGC].type == C_DOUBLE && bi_vars[ARGC].dval == 1.0 )
{ cell_destroy( bi_vars + FILENAME ) ;
bi_vars[FILENAME].type = C_STRING ;
bi_vars[FILENAME].ptr = (PTR) new_STRING( "-") ;
main_fin = FINdopen(0, 1) ;
return 1 ;
}
else return next_main() ;
}
static int next_main()
{ char xbuff[16] ;
register CELL *cp ;
STRING *sval ;
CELL argc ; /* temp copy of ARGC */
CELL tc ; /* copy of ARGV[argi] */
double d_argi ;
#ifdef DEBUG
if ( ! main_fin ) bozo("call to next_main with dead main") ;
#endif
tc.type = C_NOINIT ;
if ( main_fin != (FIN *)-1 ) FINclose(main_fin) ;
cell_destroy( bi_vars + FILENAME ) ;
cell_destroy( bi_vars + FNR ) ;
bi_vars[FNR].type = C_DOUBLE ;
bi_vars[FNR].dval = 0.0 ;
if ( cellcpy(&argc, &bi_vars[ARGC])->type != C_DOUBLE )
cast1_to_d(&argc) ;
xbuff[1] = 0 ;
d_argi = (double) argi ;
while ( d_argi < argc.dval )
{
if ( argi < 10 ) xbuff[0] = argi + '0' ;
else (void) sprintf(xbuff, "%u", argi) ;
argi++ ; d_argi += 1.0 ;
sval = new_STRING(xbuff) ;
/* the user might have changed ARGC or deleted
ARGV[argi] -- test for existence without side effects */
if ( ! array_test(Argv, sval) )
{ free_STRING(sval) ; continue ; }
cp = array_find( Argv, sval, 0) ;
free_STRING(sval) ;
/* make a copy so we can cast w/o side effect */
cell_destroy(&tc) ;
cp = cellcpy(&tc, cp) ;
if ( cp->type < C_STRING ) cast1_to_s(cp) ;
if ( string(cp)->len == 0 ) continue ;
if ( string(cp)->len == 1 && string(cp)->str[0] == '-' )
{ /* input from stdin */
main_fin = FINdopen(0,1) ;
}
else /* it might be a command line assignment */
if ( is_cmdline_assign(string(cp)->str) ) continue ;
else /* try to open it */
if ( ! (main_fin = FINopen( string(cp)->str, 1 )) ) continue ;
/* success */
(void) cellcpy( &bi_vars[FILENAME] , cp ) ;
free_STRING( string(cp) ) ;
return 1 ;
}
/* failure */
bi_vars[FILENAME].type = C_STRING ;
bi_vars[FILENAME].ptr = (PTR) new_STRING( "" ) ;
main_fin = (FIN *) 0 ;
cell_destroy(&tc) ;
return 0 ;
}
static int is_cmdline_assign(s)
char *s ;
{ char *q;
unsigned char *p ;
int c ;
SYMTAB *stp ;
CELL *cp ;
if ( scan_code[*(unsigned char *)s] != SC_IDCHAR
|| !(q = strchr(s,'=')) ) return 0 ;
p = (unsigned char *)s+1 ;
while ( (c = scan_code[*p]) == SC_IDCHAR || c == SC_DIGIT ) p++ ;
if ( (char *)p < q ) return 0 ;
*q = 0 ;
stp = find(s) ;
switch( stp->type )
{
case ST_NONE :
stp->type = ST_VAR ;
stp->stval.cp = cp = new_CELL() ;
break ;
case ST_VAR :
cp = stp->stval.cp ;
break ;
default :
rt_error(
"cannot command line assign to %s\n\t- type clash or keyword"
, s ) ;
}
*q++ = '=' ;
cp->ptr = (PTR) new_STRING(q) ;
check_strnum(cp) ;
return 1 ;
}
@//E*O*F mawk0.97/fin.c//
chmod u=rw,g=r,o=r mawk0.97/fin.c
echo x - mawk0.97/fin.h
sed 's/^@//' > "mawk0.97/fin.h" <<'@//E*O*F mawk0.97/fin.h//'
/********************************************
fin.h
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the Awk programming language as defined in
Aho, Kernighan and Weinberger, The AWK Programming Language,
Addison-Wesley, 1988.
See the accompaning file, LIMITATIONS, for restrictions
regarding modification and redistribution of this
program in source or binary form.
********************************************/
/*$Log: fin.h,v $
* Revision 2.1 91/04/08 08:23:11 brennan
* VERSION 0.97
*
*/
/* fin.h */
#ifndef FIN_H
#define FIN_H
/* structure to control input files */
typedef struct {
int fd ;
FILE *fp ; /* NULL unless interactive */
char *buff ;
char *buffp ;
short flags ;
} FIN ;
#define MAIN_FLAG 1 /* part of main input stream if on */
#define EOF_FLAG 2
FIN * PROTO (FINdopen, (int, int) );
FIN * PROTO (FINopen, (char *, int) );
void PROTO (FINclose, (FIN *) ) ;
char* PROTO (FINgets, (FIN *, unsigned *) ) ;
unsigned PROTO ( fillbuff, (int, char *, unsigned) ) ;
extern FIN *main_fin ; /* for the main input stream */
int PROTO( open_main, (void) ) ;
#endif /* FIN_H */
@//E*O*F mawk0.97/fin.h//
chmod u=rw,g=r,o=r mawk0.97/fin.h
echo x - mawk0.97/hash.c
sed 's/^@//' > "mawk0.97/hash.c" <<'@//E*O*F mawk0.97/hash.c//'
/********************************************
hash.c
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the Awk programming language as defined in
Aho, Kernighan and Weinberger, The AWK Programming Language,
Addison-Wesley, 1988.
See the accompaning file, LIMITATIONS, for restrictions
regarding modification and redistribution of this
program in source or binary form.
********************************************/
/* $Log: hash.c,v $
* Revision 2.1 91/04/08 08:23:13 brennan
* VERSION 0.97
*
*/
/* hash.c */
#include "mawk.h"
#include "memory.h"
#include "symtype.h"
#include <string.h>
unsigned hash(s)
register char *s ;
{ register unsigned h = 0 ;
while ( *s ) h += h + *s++ ;
return h ;
}
typedef struct hash {
struct hash *link ;
SYMTAB symtab ;
} HASHNODE ;
static HASHNODE *PROTO( delete, (char *) ) ;
#define new_HASHNODE() (HASHNODE *) zmalloc(sizeof(HASHNODE))
static HASHNODE *hash_table[HASH_PRIME] ;
/*
* insert -- s is not there and need not be duplicated
* -- used during initialization
*/
SYMTAB *insert(s)
char *s ;
{ register HASHNODE *p = new_HASHNODE();
register unsigned h ;
p->link = hash_table[h = hash(s) % HASH_PRIME ] ;
p->symtab.name = s ;
hash_table[h] = p ;
return &p->symtab ;
}
/*
* find -- s might be there, find it else insert and dup
* s
*/
SYMTAB *find(s)
char *s ;
{ register HASHNODE *p ;
HASHNODE *q ;
unsigned h ;
p = hash_table[h = hash(s) % HASH_PRIME ] ;
q = (HASHNODE *) 0 ;
while ( 1 )
{ if ( !p )
{ p = new_HASHNODE() ;
p->symtab.type = ST_NONE ;
p->symtab.name = strcpy(zmalloc( strlen(s)+1 ), s) ;
break ;
}
if ( strcmp(p->symtab.name, s) == 0 ) /* found */
if ( !q ) /* already at the front */
return &p->symtab ;
else /* delete from the list */
{ q->link = p->link ; break ; }
q = p ; p = p->link ;
}
/* put p on front of the list */
p->link = hash_table[h] ;
hash_table[h] = p ;
return & p->symtab ;
}
/* remove a node from the hash table
return a ptr to the node */
static unsigned last_hash ;
static HASHNODE *delete( s )
char *s ;
{ register HASHNODE *p ;
HASHNODE *q = (HASHNODE *) 0 ;
unsigned h ;
p = hash_table[ last_hash = h = hash(s) % HASH_PRIME ] ;
while ( p )
if ( strcmp(p->symtab.name, s) == 0 ) /* found */
{
if ( q ) q->link = p->link ;
else hash_table[h] = p->link ;
return p ;
}
else { q = p ; p = p->link ; }
#ifdef DEBUG /* we should not ever get here */
bozo("delete") ;
#endif
return (HASHNODE *) 0 ;
}
/* when processing user functions, global ids which are
replaced by local ids are saved on this list */
static HASHNODE *save_list ;
/* store a global id on the save list,
return a ptr to the local symtab */
SYMTAB *save_id( s )
char *s ;
{ HASHNODE *p, *q ;
unsigned h ;
p = delete(s) ;
q = new_HASHNODE() ;
q->symtab.type = ST_LOCAL_NONE ;
q->symtab.name = p->symtab.name ;
/* put q in the hash table */
q->link = hash_table[ h = last_hash ] ;
hash_table[h] = q ;
/* save p */
p->link = save_list ; save_list = p ;
return & q->symtab ;
}
/* restore all global indentifiers */
void restore_ids()
{ register HASHNODE *p, *q ;
register unsigned h ;
q = save_list ; save_list = (HASHNODE *) 0 ;
while ( q )
{
p = q ; q = q->link ;
zfree( delete(p->symtab.name) , sizeof(HASHNODE) ) ;
p->link = hash_table[h = last_hash ] ;
hash_table[h] = p ;
}
}
@//E*O*F mawk0.97/hash.c//
chmod u=rw,g=r,o=r mawk0.97/hash.c
echo x - mawk0.97/init.c
sed 's/^@//' > "mawk0.97/init.c" <<'@//E*O*F mawk0.97/init.c//'
/********************************************
init.c
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the Awk programming language as defined in
Aho, Kernighan and Weinberger, The AWK Programming Language,
Addison-Wesley, 1988.
See the accompaning file, LIMITATIONS, for restrictions
regarding modification and redistribution of this
program in source or binary form.
********************************************/
/* $Log: init.c,v $
* Revision 2.2 91/04/09 12:39:08 brennan
* added static to funct decls to satisfy STARDENT compiler
*
* Revision 2.1 91/04/08 08:23:15 brennan
* VERSION 0.97
*
*/
/* init.c */
#include "mawk.h"
#include "code.h"
#include "init.h"
#include "memory.h"
#include "symtype.h"
#include "bi_vars.h"
#include "field.h"
#define PROGRAM_FROM_CMDLINE 1
/* static protos */
static void PROTO( no_program, (void) ) ;
static void PROTO( process_cmdline , (int, char **) ) ;
static void PROTO( set_FS, (char *) ) ;
static void PROTO( set_dump, (char *) ) ;
#if DOS && ! HAVE_REARGV
#include <fcntl.h>
static void PROTO(emit_prompt, (void) ) ;
#endif
union tbuff temp_buff ;
char *main_buff = temp_buff.string_buff + TEMP_BUFF_SZ ;
void initialize(argc, argv)
int argc ; char **argv ;
{
bi_vars_init() ; /* load the builtin variables */
bi_funct_init() ; /* load the builtin functions */
kw_init() ; /* load the keywords */
field_init() ;
process_cmdline(argc, argv) ;
jmp_stacks_init() ;
code_init() ;
fpe_init() ;
#if NO_STRTOD
strtod_init() ;
#endif
}
void compile_cleanup()
/* program has parsed OK, free some memory
we don't need anymore */
{
scan_cleanup() ;
jmp_stacks_cleanup() ;
code_cleanup() ;
}
static void no_program()
{ errmsg( 0, "no program") ; mawk_exit(1) ; }
int dump_code ; /* if on dump internal code */
#ifdef DEBUG
int dump_RE ; /* if on dump compiled REs */
#endif
static void set_FS(s)
char *s ;
{
cell_destroy(field+FS) ;
field[FS].type = C_STRING ;
field[FS].ptr = (PTR) new_STRING(s) ;
cast_for_split( cellcpy(&fs_shadow, field+FS) ) ;
}
#ifdef DEBUG
static void set_dump(s)
char *s ;
{
while ( 1 )
{ switch ( *s )
{ case 'p' :
case 'P' : yydebug = 1 ; break ;
case 'c' :
case 'C' : dump_code = 1 ; break ;
case 'r' :
case 'R' : dump_RE = 1 ; break ;
case 0 :
if ( s[-1] == 'D' ) dump_code = 1 ;
return ;
default : break ;
}
s++ ;
}
}
#else
static void set_dump(s)
char *s ;
{ dump_code = 1 ; }
#endif
static void process_cmdline(argc, argv)
int argc ; char **argv ;
{ extern int program_fd ;
int i ; /* index to walk command line */
char *p ;
CELL *cp ;
SYMTAB *st_p ;
char xbuff[20] ;
for( i = 1 ; i < argc && argv[i][0] == '-' ; i++ )
{ p = & argv[i][1] ;
if ( *p == 'F' ) set_FS(p+1) ;
else if ( *p == 'D' ) set_dump(p+1) ;
else if ( *p == 'f' )
{ if ( i == argc - 1 ) no_program() ;
scan_init(! PROGRAM_FROM_CMDLINE, argv[i+1] ) ;
i += 2 ;
goto set_ARGV ;
}
}
#if DOS && ! HAVE_REARGV
/* allows short programs to be typed in without mucking stdin */
emit_prompt() ;
scan_init(! PROGRAM_FROM_CMDLINE, "CON") ;
#else /* the real world */
if ( i == argc ) no_program() ;
scan_init(PROGRAM_FROM_CMDLINE, argv[i]) ;
i++ ;
#endif
set_ARGV:
/* now set up ARGC and ARGV */
st_p = insert( "ARGV" ) ;
st_p->type = ST_ARRAY ;
Argv = st_p->stval.array = new_ARRAY() ;
xbuff[0] = '0' ; xbuff[1] = 0 ;
cp = array_find( st_p->stval.array, xbuff, 1) ;
cp->type = C_STRING ;
cp->ptr = (PTR) new_STRING( progname ) ;
/* ARGV[0] is set, do the rest
The type of ARGV[1] ... should be C_MBSTRN
because the user might enter numbers from the command line */
{ int arg_count = 1 ;
for( ; i < argc ; i++, arg_count++ )
{
if ( arg_count < 10 ) xbuff[0] = arg_count + '0' ;
else (void) sprintf(xbuff, "%u" , arg_count ) ;
cp = array_find( st_p->stval.array, xbuff, 1) ;
cp->type = C_MBSTRN ;
cp->ptr = (PTR) new_STRING( argv[i] ) ;
}
bi_vars[ARGC].type = C_DOUBLE ;
bi_vars[ARGC].dval = (double) arg_count ;
}
}
#if DOS && ! HAVE_REARGV
static void emit_prompt()
{ static char prompt[] = DOS_PROMPT ;
int fd = open("CON", O_WRONLY, 0) ;
(void) write(fd, prompt, strlen(prompt)) ;
(void) close(fd) ;
}
#endif
@//E*O*F mawk0.97/init.c//
chmod u=rw,g=r,o=r mawk0.97/init.c
echo x - mawk0.97/init.h
sed 's/^@//' > "mawk0.97/init.h" <<'@//E*O*F mawk0.97/init.h//'
/********************************************
init.h
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the Awk programming language as defined in
Aho, Kernighan and Weinberger, The AWK Programming Language,
Addison-Wesley, 1988.
See the accompaning file, LIMITATIONS, for restrictions
regarding modification and redistribution of this
program in source or binary form.
********************************************/
/* $Log: init.h,v $
* Revision 2.1 91/04/08 08:23:17 brennan
* VERSION 0.97
*
*/
/* init.h */
#ifndef INIT_H
#define INIT_H
void PROTO( initialize, (int, char **) ) ;
void PROTO( code_init, (void) ) ;
void PROTO( code_cleanup, (void) ) ;
void PROTO( compile_cleanup, (void) ) ;
void PROTO(scan_init, (int, char *) ) ;
void PROTO(scan_cleanup, (void) ) ;
void PROTO(bi_vars_init, (void) ) ;
void PROTO(bi_funct_init, (void) ) ;
void PROTO(print_init, (void) ) ;
void PROTO(kw_init, (void) ) ;
void PROTO(jmp_stacks_init, (void) ) ;
void PROTO(jmp_stacks_cleanup, (void) ) ;
void PROTO( field_init, (void) ) ;
void PROTO( fpe_init, (void) ) ;
#endif /* INIT_H */
@//E*O*F mawk0.97/init.h//
chmod u=rw,g=r,o=r mawk0.97/init.h
echo x - mawk0.97/jmp.c
sed 's/^@//' > "mawk0.97/jmp.c" <<'@//E*O*F mawk0.97/jmp.c//'
/********************************************
jmp.c
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the Awk programming language as defined in
Aho, Kernighan and Weinberger, The AWK Programming Language,
Addison-Wesley, 1988.
See the accompaning file, LIMITATIONS, for restrictions
regarding modification and redistribution of this
program in source or binary form.
********************************************/
/* $Log: jmp.c,v $
* Revision 2.1 91/04/08 08:23:19 brennan
* VERSION 0.97
*
*/
/* this module deals with back patching jumps, breaks and continues,
and with save and restoring code when we move code.
There are three stacks. If we encounter a compile error, the
stacks are frozen, i.e., we do not attempt error recovery
on the stacks
*/
#include "mawk.h"
#include "jmp.h"
#include "code.h"
#include "sizes.h"
#include "init.h"
#include "memory.h"
extern unsigned compile_error_count ;
#define error_state (compile_error_count>0)
/* a stack to hold jumps that need to be patched */
#define JMP_STK_SZ (2*MAX_LOOP_DEPTH)
static INST **jmp_stack ;
static INST **jmp_sp ;
/*-------------------------------------*/
/* a stack to hold break or continue that need to be
patched (which is all of them) */
#define BC_SZ MAX_LOOP_DEPTH
/* the stack holds a linked list of these */
struct BC_node { /* struct for the break/continue list */
char type ; /* 'B' or 'C' */
INST *jmp ; /* the jump to patch */
struct BC_node *link ;
} ;
static struct BC_node **BC_stack ;
static struct BC_node **BC_sp ;
/*---------------------------------------*/
/* a stack to hold some pieces of code while
reorganizing loops */
#define LOOP_CODE_SZ (2*MAX_LOOP_DEPTH)
static struct loop_code {
INST *code ;
unsigned short len ;
} *loop_code_stack , *lc_sp ;
/*--------------------------------------*/
void jmp_stacks_init()
{ jmp_stack = (INST **) zmalloc(JMP_STK_SZ*sizeof(INST*)) ;
jmp_sp = jmp_stack-1 ;
BC_stack = (struct BC_node **)
zmalloc(BC_SZ*sizeof(struct BC_node*)) ;
BC_sp = BC_stack-1 ;
loop_code_stack = (struct loop_code *)
zmalloc(LOOP_CODE_SZ*sizeof(struct loop_code)) ;
lc_sp = loop_code_stack - 1 ;
}
void jmp_stacks_cleanup()
{ zfree(jmp_stack, JMP_STK_SZ*sizeof(INST*)) ;
zfree(BC_stack, BC_SZ*sizeof(struct BC_node*)) ;
zfree(loop_code_stack, LOOP_CODE_SZ*sizeof(struct loop_code)) ;
}
/*--------------------------------------*/
/* operations on the jmp_stack */
void code_jmp( jtype, target)
int jtype ; INST *target ;
{
if (error_state) return ;
/* check if a constant expression will be at top of stack,
if so replace conditional jump with jump */
if ( code_ptr[-2].op == _PUSHC && jtype != _JMP )
{ int t = test( (CELL *) code_ptr[-1].ptr ) ;
if ( jtype == _JZ && ! t ||
jtype == _JNZ && t )
{ code_ptr -= 2 ; jtype = _JMP ; }
}
if ( ! target ) /* jump will have to be patched later ,
put it on the jmp_stack */
{ if ( ++jmp_sp == jmp_stack + JMP_STK_SZ )
overflow("jmp stack" , JMP_STK_SZ ) ;
*jmp_sp = code_ptr ;
code2(jtype, 0) ;
}
else
{ INST *source = code_ptr ;
code_ptr++->op = jtype ;
code_ptr++->op = target - source ;
}
}
void patch_jmp(target) /* patch a jump on the jmp_stack */
INST *target ;
{ register INST *source ;
if ( ! error_state )
{
if ( jmp_sp <= jmp_stack-1 ) bozo("jmp stack underflow") ;
source = *jmp_sp-- ;
source[1].op = target - source ;
}
}
/*---------------------------*/
/* a stack of linked lists of BC_nodes for patching
break and continue statements. */
void BC_new() /* push an empty list on the stack */
{
if ( ! error_state )
{ if ( ++BC_sp == BC_stack + BC_SZ ) overflow("BC stack", BC_SZ) ;
* BC_sp = (struct BC_node *) 0 ;
}
}
void BC_insert(type, address)
int type ; INST *address ;
{ register struct BC_node *p ;
if ( error_state ) return ;
if ( BC_sp <= BC_stack - 1 )
{ compile_error( type == 'B' ?
"break statement outside of loop" :
"continue statement outside of loop" ) ;
return ;
}
p = (struct BC_node *) zmalloc( sizeof(struct BC_node) ) ;
p->type = type ; p->jmp = address ;
p->link = *BC_sp ; *BC_sp = p ;
}
void BC_clear(B_address, C_address)
/* patch all break and continues on list */
INST *B_address, *C_address ;
{ register struct BC_node *p , *q ;
if (error_state) return ;
if ( BC_sp <= BC_stack-1) bozo("underflow on BC stack") ;
p = *BC_sp-- ;
while ( p )
{ p->jmp[1].op = (p->type=='B' ? B_address : C_address) - p->jmp ;
q = p ; p = p->link ; zfree(q, sizeof(struct BC_node)) ;
}
}
/*---------------------------------------------*/
/* save and restore some code for reorganizing
loops on a stack */
void code_push( p, len)
INST *p ; unsigned len ;
{
if (error_state) return ;
if ( ++lc_sp == loop_code_stack + LOOP_CODE_SZ )
overflow("loop_code_stack" , LOOP_CODE_SZ) ;
if ( len )
{ lc_sp->code = (INST *) zmalloc(sizeof(INST) * len) ;
(void) memcpy(lc_sp->code, p, sizeof(INST) * len) ; }
else lc_sp->code = (INST *) 0 ;
lc_sp->len = (unsigned short) len ;
}
/* copy the code at the top of the loop code stack to target.
return the number of bytes moved */
unsigned code_pop(target)
INST *target ;
{
if (error_state) return 0 ;
if ( lc_sp <= loop_code_stack-1 ) bozo("loop code stack underflow") ;
if ( lc_sp->len )
{ (void) memcpy(target, lc_sp->code, lc_sp->len * sizeof(INST)) ;
zfree(lc_sp->code, sizeof(INST)*lc_sp->len) ; }
return lc_sp-- -> len ;
}
@//E*O*F mawk0.97/jmp.c//
chmod u=rw,g=r,o=r mawk0.97/jmp.c
echo x - mawk0.97/jmp.h
sed 's/^@//' > "mawk0.97/jmp.h" <<'@//E*O*F mawk0.97/jmp.h//'
/********************************************
jmp.h
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the Awk programming language as defined in
Aho, Kernighan and Weinberger, The AWK Programming Language,
Addison-Wesley, 1988.
See the accompaning file, LIMITATIONS, for restrictions
regarding modification and redistribution of this
program in source or binary form.
********************************************/
/* $Log: jmp.h,v $
* Revision 2.1 91/04/08 08:23:21 brennan
* VERSION 0.97
*
*/
#ifndef JMP_H
#define JMP_H
void PROTO(BC_new, (void) ) ;
void PROTO(BC_insert, (int, INST*) ) ;
void PROTO(BC_clear, (INST *, INST *) ) ;
void PROTO(code_push, (INST *, unsigned) ) ;
unsigned PROTO(code_pop, (INST *) ) ;
void PROTO(code_jmp, (int, INST *) ) ;
void PROTO(patch_jmp, (INST *) ) ;
#endif /* JMP_H */
@//E*O*F mawk0.97/jmp.h//
chmod u=rw,g=r,o=r mawk0.97/jmp.h
echo x - mawk0.97/kw.c
sed 's/^@//' > "mawk0.97/kw.c" <<'@//E*O*F mawk0.97/kw.c//'
/********************************************
kw.c
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the Awk programming language as defined in
Aho, Kernighan and Weinberger, The AWK Programming Language,
Addison-Wesley, 1988.
See the accompaning file, LIMITATIONS, for restrictions
regarding modification and redistribution of this
program in source or binary form.
********************************************/
/* $Log: kw.c,v $
* Revision 2.1 91/04/08 08:23:23 brennan
* VERSION 0.97
*
*/
/* kw.c */
#include "mawk.h"
#include "symtype.h"
#include "parse.h"
#include "init.h"
static struct kw {
char *text ;
short kw ;
} keywords[] = {
"print", PRINT,
"printf", PRINTF,
"do" , DO ,
"while" , WHILE ,
"for" , FOR ,
"break" , BREAK ,
"continue" , CONTINUE ,
"if" , IF ,
"else", ELSE ,
"in" , IN ,
"delete", DELETE ,
"split" , SPLIT ,
"match" , MATCH_FUNC ,
"BEGIN" , BEGIN,
"END" , END ,
"exit" , EXIT ,
"next" , NEXT ,
"return", RETURN,
"getline", GETLINE,
"sub" , SUB,
"gsub", GSUB,
"function", FUNCTION,
(char *) 0 , 0 } ;
/* put keywords in the symbol table */
void kw_init()
{ register struct kw *p = keywords ;
register SYMTAB *q ;
while ( p->text )
{ q = insert( p->text ) ;
q->type = ST_KEYWORD ;
q->stval.kw = p++ -> kw ;
}
}
/* find a keyword to emit an error message */
char *find_kw_str( kw_token )
int kw_token ;
{ struct kw *p = keywords ;
for( p = keywords ; p->text ; p++ )
if ( p->kw == kw_token ) return p->text ;
/* search failed */
return (char *) 0 ;
}
@//E*O*F mawk0.97/kw.c//
chmod u=rw,g=r,o=r mawk0.97/kw.c
echo x - mawk0.97/machine.h
sed 's/^@//' > "mawk0.97/machine.h" <<'@//E*O*F mawk0.97/machine.h//'
/********************************************
machine.h
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the Awk programming language as defined in
Aho, Kernighan and Weinberger, The AWK Programming Language,
Addison-Wesley, 1988.
See the accompaning file, LIMITATIONS, for restrictions
regarding modification and redistribution of this
program in source or binary form.
********************************************/
/*$Log: machine.h,v $
* Revision 2.2 91/04/09 12:39:14 brennan
* added static to funct decls to satisfy STARDENT compiler
*
* Revision 2.1 91/04/08 08:23:25 brennan
* VERSION 0.97
*
*/
/* I've attempted to isolate machine/system dependencies here.
Floating point exceptions are the biggest hassle.
If you have IEEE754 floating point, turn off floating point
traps and let the INFs and NANs go berserk. This should be
the default (see page 14 of IEEE754), but ANSI C seems to imply
they should be on (i.e., one standards committee does not talk to
the other). Anyway, define a macro TURNOFF_FPE_TRAPS() which will
probably be a 1 liner.
If you cannot turn off floating exceptions, check out
fpe_catch() in matherr.c and modify as needed for your machine.
Also you may need to define FPE_ZERODIVIDE and FPE_OVERFLOW.
If you have SysV like matherr(), use it.
If you have SysV compatible math lib , use it.
You might need to supply a macro to replace drand48(), otherwise.
(See BSD43 for no IEEE754, no matherr(), no fmod(),
no strtod(), no drand48())
If you have to be conservative with memory (e.g., small model
MsDos), a small evaluation stack (16-32) is plenty.
Recursive functions calls are the only reason you need a big
stack. The default for MsDos uses 64 which allows some
recursion without killing too many memory CELLs.
*/
/* MsDOS --
If you use command.com as the shell, entering programs on the
command line is hopeless. Command.com will always glom onto
| or < or > as redirection.
If you use a Unix style shell under DOS, then you need to
write
void reargv(int *argc, char ***argv)
which gets the arguments from your shell, and then
#define HAVE_REARGV 1
See README in dos directory
and MsDos section of manual.
*/
#ifndef MACHINE_H
#define MACHINE_H
#ifdef sun /* sun3 or sun4 with SUNOS 4.0.3 */
#define FPE_TRAPS 0
#define TURNOFF_FPE_TRAPS() /* empty, default is off */
#define HAVE_MATHERR 1
#endif
#ifdef __TURBOC__
#define DOS 1
#define SMALL_EVAL_STACK 1
#define FPE_TRAPS 0
#define TURNOFF_FPE_TRAPS() _control87(0x3f,0x3f)
#define HAVE_MATHERR 1
#endif
#ifdef ULTRIX /* V4.1 on a vax 3600 */
#define HAVE_VOID_PTR 1
#define HAVE_MATHERR 1
#define FPE_ZERODIVIDE FPE_FLTDIV_FAULT
#define FPE_OVERFLOW FPE_FLTOVF_FAULT
#endif
#ifdef BSD43 /* on a vax */
#define NO_STRTOD 1
#define NO_FMOD 1
#define srand48(x) srandom(x)
#define drand48() (((double)random())/((double)(unsigned)0x80000000))
#define vfprintf(s,f,a) _doprnt(f,a,s)
#define FPE_ZERODIVIDE FPE_FLTDIV_FAULT
#define FPE_OVERFLOW FPE_FLTOVF_FAULT
#endif
#ifdef STARDENT /* Stardent 3000, SysV R3.0 */
#define HAVE_MATHERR 1
#define FPE_TRAPS 0
#define TURNOFF_FPE_TRAPS() /* nothing */
#define HAVE_VOID_PTR 1
#endif
/* the defaults */
#ifndef HAVE_VOID_PTR
#define HAVE_VOID_PTR 0 /* no void * */
#endif
#ifndef FPE_TRAPS
#define FPE_TRAPS 1
/* floating point errors generate exceptions */
#endif
#ifndef HAVE_MATHERR
#define HAVE_MATHERR 0
/* SysV style matherr() is not available */
#endif
#ifndef NO_STRTOD
#define NO_STRTOD 0 /* default is have */
#endif
#ifndef SMALL_EVAL_STACK
#define SMALL_EVAL_STACK 0
#endif
#ifndef NO_FMOD
#define NO_FMOD 0 /* default is to have fmod() */
#endif
#define STDC_MATHERR (FPE_TRAPS && ! HAVE_MATHERR)
#ifndef DOS
#define DOS 0
#endif
#if DOS
#ifndef HAVE_REARGV
#define HAVE_REARGV 0
#endif
#define DOS_PROMPT "mawk> "
/* change to "mawk \01 " on a good day */
#endif
#endif /* MACHINE_H */
@//E*O*F mawk0.97/machine.h//
chmod u=rw,g=r,o=r mawk0.97/machine.h
echo x - mawk0.97/main.c
sed 's/^@//' > "mawk0.97/main.c" <<'@//E*O*F mawk0.97/main.c//'
/********************************************
main.c
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the Awk programming language as defined in
Aho, Kernighan and Weinberger, The AWK Programming Language,
Addison-Wesley, 1988.
See the accompaning file, LIMITATIONS, for restrictions
regarding modification and redistribution of this
program in source or binary form.
********************************************/
/* $Log: main.c,v $
* Revision 2.2 91/04/22 08:08:58 brennan
* cannot close(3) or close(4) because of bug in TurboC++ 1.0
*
* Revision 2.1 91/04/08 08:23:27 brennan
* VERSION 0.97
*
*/
/* main.c */
#include "mawk.h"
#include "code.h"
#include "init.h"
#include "fin.h"
#include "bi_vars.h"
#include "field.h"
#include "files.h"
#include <stdio.h>
#if DOS
void reargv(int *, char ***) ;
#endif
void PROTO( process, (void) ) ;
void PROTO( main_loop, (void) ) ;
extern int program_fd ;
char *progname ;
jmp_buf exit_jump, next_jump ;
int exit_code ;
main(argc , argv )
int argc ; char **argv ;
{
#if DOS
progname = "mawk" ;
#if HAVE_REARGV
reargv(&argc, &argv) ;
#endif
#else
{ char *strrchr() ;
char *p = strrchr(argv[0], '/') ;
progname = p ? p+1 : argv[0] ; }
#endif
initialize(argc, argv) ;
if ( parse() || compile_error_count ) exit(1) ;
compile_cleanup() ;
process() ;
mawk_exit( exit_code ) ;
return 0 ;
}
static void process()
{
if ( setjmp(exit_jump) )
{ if ( begin_start ) zfree(begin_start, begin_size) ;
goto the_exit ;
}
if ( begin_start )
{ (void) execute(begin_start, eval_stack-1, 0) ;
zfree( begin_start , begin_size ) ;
begin_start = (INST *) 0 ;
}
if ( main_start || end_start ) main_loop() ;
the_exit:
if ( setjmp(exit_jump) ) mawk_exit(exit_code) ;
if ( main_start ) zfree(main_start, main_size) ;
if ( end_start ) (void) execute(end_start, eval_stack-1, 0) ;
}
static void main_loop()
{ register char *p ;
unsigned len ;
/* the main file stream might already be open by a call of
getline in the BEGIN block */
if ( main_fin == (FIN *) -1 && ! open_main()
|| ! main_fin ) return ;
if ( main_start )
{
(void) setjmp(next_jump) ;
while ( p = FINgets( main_fin, &len ) )
{
if ( TEST2(bi_vars + NR) != TWO_DOUBLES )
cast2_to_d(bi_vars + NR) ;
bi_vars[NR].dval += 1.0 ;
bi_vars[FNR].dval += 1.0 ;
set_field0(p, len) ;
(void) execute( main_start, eval_stack-1, 0) ;
}
}
else /* eat main to set NR and FNR before executing END */
{ long nr ;
if ( TEST2(bi_vars+NR) != TWO_DOUBLES ) cast2_to_d(bi_vars+NR) ;
nr = (long) bi_vars[NR].dval ;
while ( FINgets( main_fin, &len ) )
{ nr++ ; bi_vars[FNR].dval += 1.0 ; }
bi_vars[NR].dval = (double) nr ;
}
}
void mawk_exit(x)
int x ;
{
#if ! DOS
close_out_pipes() ; /* no effect, if no out pipes */
#endif
exit(x) ;
}
@//E*O*F mawk0.97/main.c//
chmod u=rw,g=r,o=r mawk0.97/main.c
echo x - mawk0.97/makescan.c
sed 's/^@//' > "mawk0.97/makescan.c" <<'@//E*O*F mawk0.97/makescan.c//'
/********************************************
makescan.c
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the Awk programming language as defined in
Aho, Kernighan and Weinberger, The AWK Programming Language,
Addison-Wesley, 1988.
See the accompaning file, LIMITATIONS, for restrictions
regarding modification and redistribution of this
program in source or binary form.
********************************************/
/*$Log: makescan.c,v $
* Revision 2.1 91/04/08 08:23:29 brennan
* VERSION 0.97
*
*/
/* source for makescan.exe which builds the scancode[]
via: makescan.exe > scancode.c
*/
#define MAKESCAN
#include "scan.h"
char scan_code[256] ;
void scan_init()
{
register char *p ;
(void) memset(scan_code, SC_UNEXPECTED, sizeof(scan_code)) ;
for( p = scan_code + '0' ; p <= scan_code + '9' ; p++ )
*p = SC_DIGIT ;
scan_code[0] = 0 ;
scan_code[ ' ' ] = scan_code['\t'] = scan_code['\f'] = SC_SPACE ;
scan_code[ '\r'] = scan_code['\013'] = SC_SPACE ;
scan_code[';'] = SC_SEMI_COLON ;
scan_code['\n'] = SC_NL ;
scan_code['{'] = SC_LBRACE ;
scan_code[ '}'] = SC_RBRACE ;
scan_code['+'] = SC_PLUS ;
scan_code['-'] = SC_MINUS ;
scan_code['*'] = SC_MUL ;
scan_code['/'] = SC_DIV ;
scan_code['%'] = SC_MOD ;
scan_code['^'] = SC_POW ;
scan_code['('] = SC_LPAREN ;
scan_code[')'] = SC_RPAREN ;
scan_code['_'] = SC_IDCHAR ;
scan_code['='] = SC_EQUAL ;
scan_code['#'] = SC_COMMENT ;
scan_code['\"'] = SC_DQUOTE ;
scan_code[','] = SC_COMMA ;
scan_code['!'] = SC_NOT ;
scan_code['<'] = SC_LT ;
scan_code['>'] = SC_GT ;
scan_code['|'] = SC_OR ;
More information about the Alt.sources
mailing list