Exemple #1
0
   /* argv[i] = ARGV[i] */
static void
set_ARGV(int argc, char **argv, int i)
{
    SYMTAB *st_p;
    CELL argi;
    register CELL *cp;

    st_p = insert("ARGV");
    st_p->type = ST_ARRAY;
    Argv = st_p->stval.array = new_ARRAY();
    no_leaks_array(Argv);
    argi.type = C_DOUBLE;
    argi.dval = 0.0;
    cp = array_find(st_p->stval.array, &argi, CREATE);
    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 */

    for (argi.dval = 1.0; i < argc; i++, argi.dval += 1.0) {
	cp = array_find(st_p->stval.array, &argi, CREATE);
	cp->type = C_MBSTRN;
	cp->ptr = (PTR) new_STRING(argv[i]);
    }
    ARGC->type = C_DOUBLE;
    ARGC->dval = argi.dval;
}
Exemple #2
0
/* initialize $0 and the pseudo fields */
void
field_init(void)
{
    field[0].type = C_STRING;
    field[0].ptr = (PTR) & null_str;
    null_str.ref_cnt++;

    load_pfield("NF", NF);
    NF->type = C_DOUBLE;
    NF->dval = 0.0;

    load_pfield("RS", RS);
    RS->type = C_STRING;
    RS->ptr = (PTR) new_STRING("\n");
    /* rs_shadow already set */

    load_pfield("FS", FS);
    FS->type = C_STRING;
    FS->ptr = (PTR) new_STRING(" ");
    /* fs_shadow is already set */

    load_pfield("OFMT", OFMT);
    OFMT->type = C_STRING;
    OFMT->ptr = (PTR) new_STRING("%.6g");

    load_pfield("CONVFMT", CONVFMT);
    CONVFMT->type = C_STRING;
    CONVFMT->ptr = OFMT->ptr;
    string(OFMT)->ref_cnt++;
}
Exemple #3
0
static void
set_rs_shadow()
{
   CELL c ;
   STRING *sval ;
   char *s ;
   unsigned len ;

   if (posix_space_flag && mawk_state == EXECUTION)
      scan_code['\n'] = SC_UNEXPECTED ;

   if (rs_shadow.type == SEP_STR)
      free_STRING((STRING *) rs_shadow.ptr) ;

   cast_for_split(cellcpy(&c, 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 */
	 if (mawk_state == EXECUTION)  scan_code['\n'] = SC_SPACE ;
	 rs_shadow.type = SEP_MLR ;
	 sval = new_STRING("\n\n+") ;
	 rs_shadow.ptr = re_compile(sval) ;
	 free_STRING(sval) ;
	 break ;

      default:
	 bozo("bad cell in set_rs_shadow") ;
   }
}
Exemple #4
0
void
cast1_to_s(CELL * cp)
{
    register Int lval;
    char xbuff[260];

    switch (cp->type) {
    case C_NOINIT:
	null_str.ref_cnt++;
	cp->ptr = (PTR) & null_str;
	break;

    case C_DOUBLE:

	lval = d_to_I(cp->dval);
	if (lval == cp->dval)
	    sprintf(xbuff, INT_FMT, lval);
	else
	    sprintf(xbuff, string(CONVFMT)->str, cp->dval);

	cp->ptr = (PTR) new_STRING(xbuff);
	break;

    case C_STRING:
	return;

    case C_MBSTRN:
    case C_STRNUM:
	break;

    default:
	bozo("bad type on cast");
    }
    cp->type = C_STRING;
}
Exemple #5
0
void
load_environ(ARRAY ENV)
{
    CELL c;
    register char **p = environ;	/* walks environ */
    char *s;			/* looks for the '=' */
    CELL *cp;			/* pts at ENV[&c] */

    c.type = C_STRING;

    while (*p) {
	if ((s = strchr(*p, '='))) {	/* shouldn't fail */
	    size_t len = (size_t) (s - *p);
	    c.ptr = (PTR) new_STRING0(len);
	    memcpy(string(&c)->str, *p, len);
	    s++;

	    cp = array_find(ENV, &c, CREATE);
	    cp->type = C_MBSTRN;
	    cp->ptr = (PTR) new_STRING(s);

	    free_STRING(string(&c));
	}
	p++;
    }
}
Exemple #6
0
static ANODE* find_by_ival(
    ARRAY A ,
    Int ival ,
    int create_flag ,
    int *redo )
{
    DUAL_LINK *table = (DUAL_LINK*) A->ptr ;
    unsigned indx = (unsigned) ival & A->hmask ;
    ANODE *p = table[indx].ilink ; /* walks ilist */
    ANODE *q = (ANODE*) 0 ; /* trails p */
    while(1) {
        if (!p) {
            /* search failed */
            if (A->type & AY_STR) {
                /* need to search by string */
                char buff[256] ;
                STRING *sval ;
                sprintf(buff, INT_FMT, ival) ;
                sval = new_STRING(buff) ;
                p = find_by_sval(A, sval, create_flag, redo) ;
                if (*redo) {
                    table = (DUAL_LINK*) A->ptr ;
                }
                free_STRING(sval) ;
                if (!p) return (ANODE*) 0 ;
            }
            else if (create_flag) {
                p = ZMALLOC(ANODE) ;
                p->sval = (STRING*) 0 ;
                p->cell.type = C_NOINIT ;
                if (++A->size > A->limit) {
                    double_the_hash_table(A) ; /* changes table, may change index */
                    table = (DUAL_LINK*) A->ptr ;
                    indx = A->hmask & (unsigned) ival ;
                }
            }
            else return (ANODE*) 0 ;
            p->ival = ival ;
            A->type |= AY_INT ;

            break ;
        }
        else if (p->ival == ival) {
            /* found it, now move to the front */
            if (!q) /* already at the front */
                return p ;
            /* delete for insertion at the front */
            q->ilink = p->ilink ;
            break ;
        }
        q = p ;
        p = q->ilink ;
    }
    /* insert at the front */
    p->ilink = table[indx].ilink ;
    table[indx].ilink = p ;
    return p ;
}
Exemple #7
0
static void
set_main_to_stdin(void)
{
    cell_destroy(FILENAME);
    FILENAME->type = C_STRING;
    FILENAME->ptr = (PTR) new_STRING("-");
    cell_destroy(FNR);
    FNR->type = C_DOUBLE;
    FNR->dval = 0.0;
    rt_fnr = 0;
    main_fin = FINdopen(0, 1);
}
Exemple #8
0
void
set_binmode(int x)
{
    CELL c;
    int change = ((x & 4) == 0);

    /* set RS */
    c.type = C_STRING;
    c.ptr = (PTR) new_STRING((change && (x & 1)) ? "\r\n" : "\n");
    field_assign(RS, &c);
    free_STRING(string(&c));

    /* set ORS */
    cell_destroy(ORS);
    ORS->type = C_STRING;
    ORS->ptr = (PTR) new_STRING((change && (x & 2)) ? "\r\n" : "\n");

    cell_destroy(BINMODE);
    BINMODE->type = C_DOUBLE;
    BINMODE->dval = (double) x;
}
Exemple #9
0
void
cast_for_split(CELL * cp)
{
    static char meta[] = "^$.*+?|[]()";
    static char xbuff[] = "\\X";
    int c;
    size_t len;

    if (cp->type < C_STRING)
	cast1_to_s(cp);

    if ((len = string(cp)->len) == 1) {
	if ((c = string(cp)->str[0]) == ' ') {
	    free_STRING(string(cp));
	    cp->type = C_SPACE;
	    return;
	} else if (c == 0) {
#ifdef LOCAL_REGEXP
	    char temp[1];
	    temp[0] = (char) c;
	    free_STRING(string(cp));
	    cp->ptr = (PTR) new_STRING1(temp, (size_t) 1);
#else
	    /*
	     * A null is not a meta character, but strchr will match it anyway.
	     * For now, there's no reason to compile a null as a regular
	     * expression - just return a string containing the single
	     * character.  That is used in a special case in set_rs_shadow().
	     */
	    char temp[2];
	    temp[0] = (char) c;
	    free_STRING(string(cp));
	    cp->ptr = (PTR) new_STRING1(temp, (size_t) 1);
	    return;
#endif
	} else if (strchr(meta, c)) {
	    xbuff[1] = (char) c;
	    free_STRING(string(cp));
	    cp->ptr = (PTR) new_STRING(xbuff);
	}
    } else if (len == 0) {
	free_STRING(string(cp));
	cp->type = C_SNULL;
	return;
    }

    cast_to_RE(cp);
}
Exemple #10
0
CELL* array_find(
    ARRAY A,
    CELL *cp,
    int create_flag)
{
    ANODE *ap ;
    int redid ;
    if (A->size == 0 && !create_flag)
        /* eliminating this trivial case early avoids unnecessary conversions later */
        return (CELL*) 0 ;
    switch (cp->type) {
    case C_DOUBLE:
    {
        double d = cp->dval ;
        Int ival = d_to_I(d) ;
        if ((double)ival == d) {
            if (A->type == AY_SPLIT) {
                if (ival >= 1 && ival <= (int) A->size)
                    return (CELL*)A->ptr+(ival-1) ;
                if (!create_flag) return (CELL*) 0 ;
                convert_split_array_to_table(A) ;
            }
            else if (A->type == AY_NULL) make_empty_table(A, AY_INT) ;
            ap = find_by_ival(A, ival, create_flag, &redid) ;
        }
        else {
            /* convert to string */
            char buff[260] ;
            STRING *sval ;
            sprintf(buff, string(CONVFMT)->str, d) ;
            sval = new_STRING(buff) ;
            ap = find_by_sval(A, sval, create_flag, &redid) ;
            free_STRING(sval) ;
        }
    }

    break ;
    case C_NOINIT:
        ap = find_by_sval(A, &null_str, create_flag, &redid) ;
        break ;
    default:
        ap = find_by_sval(A, string(cp), create_flag, &redid) ;
        break ;
    }
    return ap ? &ap->cell : (CELL *) 0 ;
}
Exemple #11
0
static void add_string_associations(ARRAY A)
{
    if (A->type == AY_NULL) make_empty_table(A, AY_STR) ;
    else {
        DUAL_LINK *table ;
        int i ; /* walks table */
        ANODE *p ; /* walks ilist */
        char buff[256] ;
        if (A->type == AY_SPLIT) convert_split_array_to_table(A) ;
        table = (DUAL_LINK*) A->ptr ;
        for(i=0; (unsigned) i <= A->hmask; i++) {
            p = table[i].ilink ;
            while(p) {
                sprintf(buff, INT_FMT, p->ival) ;
                p->sval = new_STRING(buff) ;
                p->hval = ahash(p->sval) ;
                p->slink = table[A->hmask&p->hval].slink ;
                table[A->hmask&p->hval].slink = p ;
                p = p->ilink ;
            }
        }
        A->type |= AY_STR ;
    }
}
Exemple #12
0
void array_delete(
    ARRAY A,
    CELL *cp)
{
    ANODE *ap ;
    int redid ;
    if (A->size == 0) return ;
    switch(cp->type) {
    case C_DOUBLE :
    {
        double d = cp->dval ;
        Int ival = d_to_I(d) ;
        if ((double)ival == d) {
            if (A->type == AY_SPLIT)
            {
                if (ival >=1 && ival <= (int) A->size)
                    convert_split_array_to_table(A) ;
                else return ; /* ival not in range */
            }
            ap = find_by_ival(A, ival, NO_CREATE, &redid) ;
            if (ap) { /* remove from the front of the ilist */
                DUAL_LINK *table = (DUAL_LINK*) A->ptr ;
                table[(unsigned) ap->ival & A->hmask].ilink = ap->ilink ;
                if (ap->sval) {
                    ANODE *p, *q = 0 ;
                    unsigned indx = (unsigned) ap->hval & A->hmask ;
                    p = table[indx].slink ;
                    while(p != ap) {
                        q = p ;
                        p = q->slink ;
                    }
                    if (q) q->slink = p->slink ;
                    else table[indx].slink = p->slink ;
                    free_STRING(ap->sval) ;
                }

                cell_destroy(&ap->cell) ;
                ZFREE(ap) ;
                if (--A->size == 0) array_clear(A) ;


            }
            return ;
        }

        else { /* get the string value */
            char buff[260] ;
            STRING *sval ;
            sprintf(buff, string(CONVFMT)->str, d) ;
            sval = new_STRING(buff) ;
            ap = find_by_sval(A, sval, NO_CREATE, &redid) ;
            free_STRING(sval) ;
        }
    }
    break ;
    case C_NOINIT :
        ap = find_by_sval(A, &null_str, NO_CREATE, &redid) ;
        break ;
    default :
        ap = find_by_sval(A, string(cp), NO_CREATE, &redid) ;
        break ;
    }
    if (ap) { /* remove from the front of the slist */
        DUAL_LINK *table = (DUAL_LINK*) A->ptr ;
        table[ap->hval & A->hmask].slink = ap->slink ;
        if (ap->ival != NOT_AN_IVALUE) {
            ANODE *p, *q = 0 ;
            unsigned indx = (unsigned) ap->ival & A->hmask ;
            p = table[indx].ilink ;
            while(p != ap) {
                q = p ;
                p = q->ilink ;
            }
            if (q) q->ilink = p->ilink ;
            else table[indx].ilink = p->ilink ;
        }

        free_STRING(ap->sval) ;
        cell_destroy(&ap->cell) ;
        ZFREE(ap) ;
        if (--A->size == 0) array_clear(A) ;


    }
}
Exemple #13
0
static void
build_field0(void)
{

#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) {
	cellcpy(field, field + 1);
    } else {
	CELL c;
	STRING *ofs, *tail;
	size_t len;
	register CELL *cp;
	register char *p, *q;
	int cnt;
	CELL **fbp, *cp_limit;

	cast1_to_s(cellcpy(&c, OFS));
	ofs = (STRING *) c.ptr;
	cast1_to_s(cellcpy(&c, field_ptr(nf)));
	tail = (STRING *) c.ptr;
	cnt = nf - 1;

	len = ((size_t) cnt) * ofs->len + tail->len;

	fbp = fbank;
	cp_limit = field + FBANK_SZ;
	cp = field + 1;

	while (cnt-- > 0) {
	    if (cp->type < C_STRING) {	/* use the string field temporarily */
		if (cp->type == C_NOINIT) {
		    cp->ptr = (PTR) & null_str;
		    null_str.ref_cnt++;
		} else {	/* its a double */
		    Int ival;
		    char xbuff[260];

		    ival = d_to_I(cp->dval);
		    if (ival == cp->dval)
			sprintf(xbuff, INT_FMT, ival);
		    else
			sprintf(xbuff, string(CONVFMT)->str, cp->dval);

		    cp->ptr = (PTR) new_STRING(xbuff);
		}
	    }

	    len += string(cp)->len;

	    if (++cp == cp_limit) {
		cp = *++fbp;
		cp_limit = cp + FBANK_SZ;
	    }

	}

	field[0].type = C_STRING;
	field[0].ptr = (PTR) new_STRING0(len);

	p = string(field)->str;

	/* walk it again , putting things together */
	cnt = nf - 1;
	fbp = fbank;
	cp = field + 1;
	cp_limit = field + FBANK_SZ;
	while (cnt-- > 0) {
	    memcpy(p, string(cp)->str, string(cp)->len);
	    p += string(cp)->len;
	    /* if not really string, free temp use of ptr */
	    if (cp->type < C_STRING) {
		free_STRING(string(cp));
	    }
	    if (++cp == cp_limit) {
		cp = *++fbp;
		cp_limit = cp + FBANK_SZ;
	    }
	    /* add the separator */
	    q = ofs->str;
	    while (*q)
		*p++ = *q++;
	}
	/* tack tail on the end */
	memcpy(p, tail->str, tail->len);

	/* cleanup */
	free_STRING(tail);
	free_STRING(ofs);
    }
}
Exemple #14
0
void
field_assign(CELL * fp, CELL * cp)
{
    CELL c;
    int i, j;

    /* the most common case first */
    if (fp == field) {
	cell_destroy(field);
	cellcpy(fp, cp);
	nf = -1;
	return;
    }

    /* its not important to do any of this fast */

    if (nf < 0)
	split_field0();

#ifdef  MSDOS
    if (!SAMESEG(fp, field)) {
	i = -1;
	goto lm_dos_label;
    }
#endif

    switch (i = (int) (fp - field)) {

    case NF_field:

	cell_destroy(NF);
	cellcpy(NF, cellcpy(&c, cp));
	if (c.type != C_DOUBLE)
	    cast1_to_d(&c);

	if ((j = d_to_i(c.dval)) < 0)
	    rt_error("negative value assigned to NF");

	if (j > nf)
	    for (i = nf + 1; i <= j; i++) {
		cp = field_ptr(i);
		cell_destroy(cp);
		cp->type = C_STRING;
		cp->ptr = (PTR) & null_str;
		null_str.ref_cnt++;
	    }

	nf = j;
	build_field0();
	break;

    case RS_field:
	cell_destroy(RS);
	cellcpy(RS, cp);
	set_rs_shadow();
	break;

    case FS_field:
	cell_destroy(FS);
	cast_for_split(cellcpy(&fs_shadow, cellcpy(FS, cp)));
	break;

    case OFMT_field:
    case CONVFMT_field:
	/* If the user does something stupid with OFMT or CONVFMT,
	   we could crash.
	   We'll make an attempt to protect ourselves here.  This is
	   why OFMT and CONVFMT are pseudo fields.

	   The ptrs of OFMT and CONVFMT always have a valid STRING,
	   even if assigned a DOUBLE or NOINIT
	 */

	free_STRING(string(fp));
	cellcpy(fp, cp);
	if (fp->type < C_STRING)	/* !! */
	    fp->ptr = (PTR) new_STRING("%.6g");
	else if (fp == CONVFMT) {
	    /* It's a string, but if it's really goofy and CONVFMT,
	       it could still damage us. Test it .
	     */
	    char xbuff[512];

	    xbuff[256] = 0;
	    sprintf(xbuff, string(fp)->str, 3.1459);
	    if (xbuff[256])
		rt_error("CONVFMT assigned unusable value");
	}
	break;

#ifdef MSDOS
      lm_dos_label:
#endif

    default:			/* $1 or $2 or ... */

	cell_destroy(fp);
	cellcpy(fp, cp);

	if (i < 0 || i > MAX_SPLIT)
	    i = field_addr_to_index(fp);

	if (i > nf) {
	    for (j = nf + 1; j < i; j++) {
		cp = field_ptr(j);
		cell_destroy(cp);
		cp->type = C_STRING;
		cp->ptr = (PTR) & null_str;
		null_str.ref_cnt++;
	    }
	    nf = i;
	    cell_destroy(NF);
	    NF->type = C_DOUBLE;
	    NF->dval = (double) i;
	}

	build_field0();

    }
}
Exemple #15
0
void  bi_vars_init()
{ register int i ;
  register SYMTAB *s ;

  
  for ( i = 0 ; i < NUM_BI_VAR ; i++ )
  { if (!strcmp(bi_var_names[i], "PROCINFO"))
      continue;
    s = insert( bi_var_names[i] ) ;
    s->type = i <= 1 ? ST_NR : ST_VAR ; 
    s->stval.cp = bi_vars + i ;
    /* bi_vars[i].type = 0 which is C_NOINIT */
  }

  s = insert("ENVIRON") ;
  s->type = ST_ENV ;

  /* set defaults */

  FILENAME->type = C_STRING ;
  FILENAME->ptr = (PTR) new_STRING( "" ) ; 

  SORTTYPE->type = C_DOUBLE ;
  SORTTYPE->dval = 0.0 ;

  OFS->type = C_STRING ;
  OFS->ptr = (PTR) new_STRING( " " ) ;
  
  ORS->type = C_STRING ;
  ORS->ptr = (PTR) new_STRING( "\n" ) ;

  SUBSEP->type = C_STRING ;
  SUBSEP->ptr =  (PTR) new_STRING( "\034" ) ;

  NF->type = C_DOUBLE ;
  NF->dval = 0.0 ;

  FIELDWIDTHS->type = C_DOUBLE ;
  FIELDWIDTHS->dval = 0.0 ;

  SAVEWIDTHS->type = C_DOUBLE ;
  SAVEWIDTHS->dval = 0.0 ;

  ARGIND->type = C_DOUBLE ;
  ARGIND->dval = 0.0 ;

  RS->type = C_STRING ;
  RS->ptr = (PTR) new_STRING("\n") ;
  /* rs_shadow already set */

  RT->type = C_STRING ;
  RT->ptr = (PTR) new_STRING("\n") ;

  FS->type = C_STRING ;
  FS->ptr = (PTR) new_STRING(" ") ;
  /* fs_shadow is already set */

  OFMT->type = C_STRING ;
  OFMT->ptr = (PTR) new_STRING("%.6g") ;

  CONVFMT->type = C_STRING ;
  CONVFMT->ptr = OFMT->ptr ;
  string(OFMT)->ref_cnt++ ;

  NR->type = FNR->type = C_DOUBLE ;

  s = insert("PROCINFO") ;
  s->type = ST_ARRAY;
  s->stval.array = new_ARRAY();
  /* PROCINFO->stval.array = new_ARRAY(); */
  /* dval is already 0.0 */

}
Exemple #16
0
static void
set_rs_shadow(void)
{
    CELL c;
    STRING *sval;
    char *s;
    unsigned len;

    if (posix_space_flag && mawk_state == EXECUTION)
	scan_code['\n'] = SC_UNEXPECTED;

    if (rs_shadow.type == SEP_STR) {
	free_STRING((STRING *) rs_shadow.ptr);
    }

    cast_for_split(cellcpy(&c, 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 */
	if (mawk_state == EXECUTION)
	    scan_code['\n'] = SC_SPACE;
	rs_shadow.type = SEP_MLR;
	sval = new_STRING("\n\n+");
	rs_shadow.ptr = re_compile(sval);
	free_STRING(sval);
	break;

    case C_STRING:
	/*
	 * Check for special case where we retained the cell as a string,
	 * bypassing regular-expression compiling.
	 */
	if (string(&c)->len == 1) {
	    rs_shadow.type = SEP_CHAR;
	    rs_shadow.c = string(&c)->str[0];
	    break;
	}
	/* FALLTHRU */
    default:
	bozo("bad cell in set_rs_shadow");
    }
}
Exemple #17
0
static int
collect_RE(void)
{
    char *p = string_buff;
    const char *first = NULL;
    int limit = sizeof(string_buff) - 2;
    int c;
    int boxed = 0;
    STRING *sval;

    while (1) {
	if (p >= (string_buff + limit)) {
	    compile_error(
			     "regular expression /%.10s ..."
			     " exceeds implementation size limit (%d)",
			     string_buff,
			     limit);
	    mawk_exit(2);
	}
	CheckStringSize(p);
	switch (scan_code[NextUChar(c = *p++)]) {
	case SC_POW:
	    /* Handle [^]] and [^^] correctly. */
	    if ((p - 1) == first && first != 0 && first[-1] == '[') {
		first = p;
	    }
	    break;

	case SC_LBOX:
	    /*
	     * If we're starting a bracket expression, remember where that
	     * started, so we can make comparisons to handle things like
	     * "[]xxxx]" and "[^]xxxx]".
	     */
	    if (!boxed) {
		first = p;
		++boxed;
	    } else {
		/* XXX. Does not handle collating symbols or equivalence
		 * class expressions. */
		/* XXX. Does not match logic used in rexp0.c to check for
		 * a character class expression, though probably the
		 * latter should be adjusted.
		 * POSIX and common sense give us license to complain about
		 * expressions such as '[[:not a special character class]]'.
		 */
		if (next() == ':') {
		    ++boxed;
		}
		un_next();
	    }
	    break;

	case SC_RBOX:
	    /*
	     * A right square-bracket loses its special meaning if it occurs
	     * first in the list (after an optional "^").
	     */
	    if (boxed && p - 1 != first) {
		--boxed;
	    }
	    break;

	case SC_DIV:		/* done */
	    if (!boxed) {
		*--p = 0;
		goto out;
	    }
	    break;

	case SC_NL:
	    p[-1] = 0;
	    /* FALLTHRU */

	case 0:		/* unterminated re */
	    compile_error(
			     "runaway regular expression /%.10s ...",
			     string_buff);
	    mawk_exit(2);

	case SC_ESCAPE:
	    switch (c = next()) {
	    case '/':
		p[-1] = '/';
		break;

	    case '\n':
		p--;
		break;

	    case 0:
		un_next();
		break;

	    default:
		*p++ = (char) c;
		break;
	    }
	    break;
	}
    }

  out:
    /* now we've got the RE, so compile it */
    sval = new_STRING(string_buff);
    yylval.ptr = re_compile(sval);
    free_STRING(sval);
    return RE;
}