int f_ztrnlnm( oprtype *a, opctype op ) { triple *r, *last, *ref; int i; bool again; last = r = maketriple(op); if (!strexpr(&r->operand[0])) return FALSE; ref = newtriple(OC_PARAMETER); last->operand[1] = put_tref(ref); if (window_token == TK_COMMA) { advancewindow(); if (window_token == TK_COMMA || window_token == TK_RPAREN) { ref->operand[0] = put_str("",0); }else { if (!strexpr(&ref->operand[0])) return FALSE; } }else { ref->operand[0] = put_str("",0); } last = ref; ref = newtriple(OC_PARAMETER); last->operand[1] = put_tref(ref); if (window_token == TK_COMMA) { advancewindow(); if (window_token == TK_COMMA || window_token == TK_RPAREN) { ref->operand[0] = put_ilit(0); }else { if (!intexpr(&ref->operand[0])) return FALSE; } }else { ref->operand[0] = put_ilit(0); } last = ref; again = TRUE; for (i = 0; i < 3; i++) { ref = newtriple(OC_PARAMETER); last->operand[1] = put_tref(ref); if (again && window_token == TK_COMMA) { advancewindow(); if (window_token == TK_COMMA || window_token == TK_RPAREN) { ref->operand[0] = put_str("",0); }else { if (!strexpr(&ref->operand[0])) return FALSE; } }else { again = FALSE; ref->operand[0] = put_str("",0); } last = ref; } ins_triple(r); *a = put_tref(r); return TRUE; }
int f_piece(oprtype *a, opctype op) { mval *delim_mval; triple *delimiter, *first, *last, *r; oprtype x; delimfmt unichar; error_def(ERR_COMMA); r = maketriple(op); if (!strexpr(&(r->operand[0]))) return FALSE; if (window_token != TK_COMMA) { stx_error(ERR_COMMA); return FALSE; } advancewindow(); delimiter = newtriple(OC_PARAMETER); r->operand[1] = put_tref(delimiter); first = newtriple(OC_PARAMETER); delimiter->operand[1] = put_tref(first); if (!strexpr(&x)) return FALSE; if (window_token != TK_COMMA) first->operand[0] = put_ilit(1); else { advancewindow(); if (!intexpr(&(first->operand[0]))) return FALSE; } assert(x.oprclass == TRIP_REF); if (window_token != TK_COMMA && x.oprval.tref->opcode == OC_LIT && (1 == ((gtm_utf8_mode && OC_FNZPIECE != op) ? MV_FORCE_LEN(&x.oprval.tref->operand[0].oprval.mlit->v) : x.oprval.tref->operand[0].oprval.mlit->v.str.len))) { /* Potential shortcut to op_fnzp1 or op_fnp1. Make some further checks */ delim_mval = &x.oprval.tref->operand[0].oprval.mlit->v; /* Both valid chars of char_len 1 and invalid chars of byte length 1 get the fast path */ unichar.unichar_val = 0; if (!gtm_utf8_mode || OC_FNZPIECE == op) { /* Single byte delimiter */ r->opcode = OC_FNZP1; unichar.unibytes_val[0] = *delim_mval->str.addr; } else { /* Potentially multiple bytes in one int */ r->opcode = OC_FNP1; assert(SIZEOF(int) >= delim_mval->str.len); memcpy(unichar.unibytes_val, delim_mval->str.addr, delim_mval->str.len); } delimiter->operand[0] = put_ilit(unichar.unichar_val); ins_triple(r); *a = put_tref(r); return TRUE; }
int m_zlink(void) { int rval; triple *ref; oprtype file, quals; if (window_token == TK_EOL || window_token == TK_SPACE || window_token == TK_COLON) { ref = newtriple(OC_SVGET); ref->operand[0] = put_ilit(SV_ZSOURCE); file = put_tref(ref); if (window_token == TK_COLON) { advancewindow(); if (!strexpr(&quals)) return FALSE; } else { ref = newtriple(OC_SVGET); ref->operand[0] = put_ilit(SV_ZCOMPILE); quals = put_tref(ref); } } else { if (!(rval = strexpr(&file))) return FALSE; if (window_token != TK_COLON) { if (rval == EXPR_INDR) { make_commarg(&file,indir_zlink); return TRUE; } ref = newtriple(OC_SVGET); ref->operand[0] = put_ilit(SV_ZCOMPILE); quals = put_tref(ref); } else { advancewindow(); if (!strexpr(&quals)) return FALSE; } } ref = newtriple(OC_ZLINK); ref->operand[0] = file; ref->operand[1] = quals; return TRUE; }
int f_extract(oprtype *a, opctype op) { triple *first, *last, *r; r = maketriple(op); if (!strexpr(&(r->operand[0]))) return FALSE; first = newtriple(OC_PARAMETER); last = newtriple(OC_PARAMETER); r->operand[1] = put_tref(first); first->operand[1] = put_tref(last); if (window_token != TK_COMMA) { first->operand[0] = last->operand[0] = put_ilit(1); } else { advancewindow(); if (!intexpr(&(first->operand[0]))) return FALSE; if (window_token != TK_COMMA) last->operand[0] = first->operand[0]; else { advancewindow(); if (!intexpr(&(last->operand[0]))) return FALSE; } } ins_triple(r); *a = put_tref(r); return TRUE; }
int f_justify( oprtype *a, opctype op) { triple *ref, *r; error_def(ERR_COMMA); r = maketriple(op); if (!strexpr(&r->operand[0])) return FALSE; if (window_token != TK_COMMA) { stx_error(ERR_COMMA); return FALSE; } advancewindow(); if (!intexpr(&r->operand[1])) return FALSE; if (window_token == TK_COMMA) { r->opcode = OC_FNJ3; ref = newtriple(OC_PARAMETER); ref->operand[0] = r->operand[1]; r->operand[1] = put_tref(ref); advancewindow(); if (!intexpr(&ref->operand[1])) return FALSE; } ins_triple(r); *a = put_tref(r); return TRUE; }
int m_zsystem(void) { oprtype x; triple *triptr; if (window_token == TK_EOL || window_token == TK_SPACE) { triptr = newtriple(OC_ZSYSTEM); triptr->operand[0] = put_str("",0); return TRUE; } else switch (strexpr(&x)) { case EXPR_FAIL: return FALSE; case EXPR_GOOD: triptr = newtriple(OC_ZSYSTEM); triptr->operand[0] = x; return TRUE; case EXPR_INDR: make_commarg(&x,indir_zsystem); return TRUE; } return FALSE; /* This will never get executed, added to make compiler happy */ }
int m_xecute(void) { triple tmpchain, *oldchain, *obp, *ref0, *ref1, *triptr; oprtype *cr, x; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; dqinit(&tmpchain,exorder); oldchain = setcurtchain(&tmpchain); switch (strexpr(&x)) { case EXPR_FAIL: setcurtchain(oldchain); return FALSE; case EXPR_INDR: if (window_token != TK_COLON) { make_commarg(&x,indir_xecute); break; } /* caution: fall through */ case EXPR_GOOD: ref0 = maketriple(OC_COMMARG); ref0->operand[0] = x; ref0->operand[1] = put_ilit(indir_linetail); ins_triple(ref0); } setcurtchain(oldchain); if (window_token == TK_COLON) { advancewindow(); cr = (oprtype *) mcalloc(SIZEOF(oprtype)); if (!bool_expr((bool) FALSE,cr)) return FALSE; if (TREF(expr_start) != TREF(expr_start_orig)) { triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(TREF(expr_start)); } obp = oldchain->exorder.bl; dqadd(obp,&tmpchain,exorder); /* violates info hiding */ if (TREF(expr_start) != TREF(expr_start_orig)) { ref0 = newtriple(OC_JMP); ref1 = newtriple(OC_GVRECTARG); ref1->operand[0] = put_tref(TREF(expr_start)); *cr = put_tjmp(ref1); tnxtarg(&ref0->operand[0]); } else tnxtarg(cr); return TRUE; } obp = oldchain->exorder.bl; dqadd(obp,&tmpchain,exorder); /* violates info hiding */ return TRUE; }
int f_zgetsyi( oprtype *a, opctype op) { triple *r; r = maketriple(op); if (!strexpr(&(r->operand[0]))) return FALSE; if (window_token != TK_COMMA) r->operand[1] = put_str("",0); else { advancewindow(); if (!strexpr(&r->operand[1])) return FALSE; } ins_triple(r); *a = put_tref(r); return TRUE; }
int f_qlength(oprtype *a, opctype op) { triple *r; r = maketriple(op); if (!strexpr(&(r->operand[0]))) return FALSE; ins_triple(r); *a = put_tref(r); return TRUE; }
int f_two_mstrs( oprtype *a, opctype op) { triple *r; error_def(ERR_COMMA); r = maketriple(op); if (!strexpr(&(r->operand[0]))) return FALSE; if (window_token != TK_COMMA) { stx_error(ERR_COMMA); return FALSE; } advancewindow(); if (!strexpr(&r->operand[1])) { return FALSE; } ins_triple(r); *a = put_tref(r); return TRUE; }
int main(int argc, char *argv[]) { int result; if (argc < 2) fatal("Usage: sexpr expression ...\n"); while (--argc > 0) { if (strexpr(&result, *++argv)) fatal("expression error\n"); printf("%s = %d\n", argv[0] , result); } exit(0); }
int f_zjobexam(oprtype *a, opctype op) { triple *r; r = maketriple(op); if (TK_RPAREN == window_token) { /* No argument specified - default to null */ r->operand[0] = put_str("",0); } else if (!strexpr(&(r->operand[0]))) return FALSE; /* Improper string argument */ ins_triple(r); *a = put_tref(r); return TRUE; }
int f_stack(oprtype *a, opctype op) { triple *r; r = maketriple(op); if (!intexpr(&(r->operand[0]))) return FALSE; if (window_token == TK_COMMA) { advancewindow(); r->opcode = OC_FNSTACK2; /*This isn't very good information hiding*/ if (!strexpr(&(r->operand[1]))) return FALSE; } ins_triple(r); *a = put_tref(r); return TRUE; }
int m_set(void) { /* Some comment on "parse_warn". It is set to TRUE whenever the parse encounters an invalid setleft target. * Note that even if "parse_warn" is TRUE, we should not return FALSE right away but need to continue the parse * until the end of the current SET command. This way any remaining commands in the current parse line will be * parsed and triples generated for them. This is necessary just in case the currently parsed invalid SET command * does not get executed at runtime (due to postconditionals etc.) * * Some comment on the need for "first_setleft_invalid". This variable is needed only in the * case we encounter an invalid-SVN/invalid-FCN/unsettable-SVN as a target of the SET. We need to evaluate the * right-hand-side of the SET command only if at least one valid setleft target is parsed before an invalid setleft * target is encountered. This is because we still need to execute the valid setlefts at runtime before triggering * a runtime error for the invalid setleft. If the first setleft target is an invalid one, then there is no need * to evaluate the right-hand-side. In fact, in this case, adding triples (corresponding to the right hand side) * to the execution chain could cause problems with emit_code later in the compilation as the destination * for the right hand side triples could now be undefined (for example a valid SVN on the left side of the * SET would have generated an OC_SVPUT triple with one of its operands holding the result of the right * hand side evaluation, but an invalid SVN on the left side which would have instead caused an OC_RTERROR triple * to have been generated leaving no triple to receive the result of the right hand side evaluation thus causing * emit_code to be confused and GTMASSERT). Therefore discard all triples generated by the right hand side in this case. * By the same reasoning, discard all triples generated by setleft targets AFTER this invalid one as well. * "first_setleft_invalid" is set to TRUE if the first setleft target is invalid and set to FALSE if the first setleft * target is valid. It is initialized to -1 before the start of the parse. */ int index, setop, delimlen; int first_val_lit, last_val_lit, nakedzalias; boolean_t first_is_lit, last_is_lit, got_lparen, delim1char, is_extract, valid_char; boolean_t alias_processing, have_lh_alias; opctype put_oc; oprtype v, delimval, firstval, lastval, *result, resptr; triple *curtargchain, *delimiter, discardcurtchain, *first, *get, *jmptrp1, *jmptrp2, *last, *obp, *put; triple *s, *s0, *s1, save_targchain, *save_curtchain, *save_curtchain1, *sub, targchain, *tmp; mint delimlit; mval *delim_mval; mvar *mvarptr; boolean_t parse_warn; /* set to TRUE in case of an invalid SVN etc. */ boolean_t curtchain_switched; /* set to TRUE if a setcurtchain was done */ int first_setleft_invalid; /* set to TRUE if the first setleft target is invalid */ boolean_t temp_subs_was_FALSE; union { uint4 unichar_val; unsigned char unibytes_val[4]; } unichar; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; TREF(temp_subs) = FALSE; dqinit(&targchain, exorder); result = (oprtype *)mcalloc(SIZEOF(oprtype)); resptr = put_indr(result); delimiter = sub = last = NULL; /* A SET clause must be entirely alias related or a normal set. Parenthized multiple sets of aliases are not allowed * and will trigger an error. This is because the source and targets of aliases require different values and references * than normal sets do and thus cannot be mixed. */ if (alias_processing = (TK_ASTERISK == window_token)) advancewindow(); if (got_lparen = (TK_LPAREN == window_token)) { if (alias_processing) stx_error(ERR_NOALIASLIST); advancewindow(); TREF(temp_subs) = TRUE; } /* Some explanation: The triples from the left hand side of the SET expression that are * expressly associated with fetching (in case of set $piece/$extract) and/or storing of * the target value are removed from curtchain and placed on the targchain. Later, these * triples will be added to the end of curtchain to do the finishing store of the target * after the righthand side has been evaluated. This is per the M standard. * * Note that SET $PIECE/$EXTRACT have special conditions in which the first argument is not referenced at all. * (e.g. set $piece(^a," ",3,2) in this case 3 > 2 so this should not evaluate ^a and therefore should not * modify the naked indicator). That is, the triples that do these conditional checks need to be inserted * ahead of the OC_GVNAME of ^a, all of which need to be inserted on the targchain. But the conditionalization * can be done only after parsing the first argument of the SET $PIECE and examining the remaining arguments. * Therefore we maintain the "curtargchain" variable which stores the value of the "targchain" at the beginning * of the iteration (at the start of the $PIECE parsing) and all the conditionalization will be inserted right * here which is guaranteed to be ahead of where the OC_GVNAME gets inserted. * * For example, SET $PIECE(^A(x,y),delim,first,last)=RHS will generate a final triple chain as follows * * A - Triples to evaluate subscripts (x,y) of the global ^A * A - Triples to evaluate delim * A - Triples to evaluate first * A - Triples to evaluate last * B - Triples to evaluate RHS * C - Triples to do conditional check (e.g. first > last etc.) * C - Triples to branch around if the checks indicate this is a null operation SET $PIECE * D - Triple that does OC_GVNAME of ^A * D - Triple that does OC_SETPIECE to determine the new value * D - Triple that does OC_GVPUT of the new value into ^A(x,y) * This is the point where the conditional check triples will branch around to if they chose to. * * A - triples that evaluates the arguments/subscripts in the left-hand-side of the SET command * These triples are built in "curtchain" * B - triples that evaluates the arguments/subscripts in the right-hand-side of the SET command * These triples are built in "curtchain" * C - triples that do conditional check for any $PIECE/$EXTRACT in the left side of the SET command. * These triples are built in "curtargchain" * D - triples that generate the reference to the target of the SET and the store into the target. * These triples are built in "targchain" * * Note alias processing does not support the SET *(...)=.. type syntax because the type of argument * created for RHS processing is dependent on the LHS receiver type and we do not support more than one * type of source argument in a single SET. */ first_setleft_invalid = FIRST_SETLEFT_NOTSEEN; curtchain_switched = FALSE; nakedzalias = have_lh_alias = FALSE; save_curtchain = NULL; assert(FIRST_SETLEFT_NOTSEEN != TRUE); assert(FIRST_SETLEFT_NOTSEEN != FALSE); for (parse_warn = FALSE; ; parse_warn = FALSE) { curtargchain = targchain.exorder.bl; jmptrp1 = jmptrp2 = NULL; delim1char = is_extract = FALSE; allow_dzwrtac_as_mident(); /* Allows $ZWRTACxxx as target to be treated as an mident */ switch (window_token) { case TK_IDENT: /* A slight diversion first. If this is a $ZWRTAC set (indication of $ in first char * is currently enough to signify that), then we need to check a few conditions first. * If this is a "naked $ZWRTAC", meaning no numeric suffix, then this is a flag that * all the $ZWRTAC vars in the local variable tree need to be kill *'d which will not * be generating a SET instruction. First we need to verify that fact and make sure * we are not in PARENs and not doing alias processing. Note *any* value can be * specified as the source but while it will be evaluated, it is NOT stored anywhere. */ if ('$' == *window_ident.addr) { /* We have a $ZWRTAC<xx> target */ if (got_lparen) /* We don't allow $ZWRTACxxx to be specified in a parenthesized list. * Verify that first */ SYNTAX_ERROR(ERR_DZWRNOPAREN); if (STR_LIT_LEN(DOLLAR_ZWRTAC) == window_ident.len) { /* Ok, this is a naked $ZWRTAC targeted set */ if (alias_processing) SYNTAX_ERROR(ERR_DZWRNOALIAS); nakedzalias = TRUE; /* This opcode doesn't really need args but it is easier to fit in with the rest * of m_set processing to pass it the result arg, which there may actually be * a use for someday.. */ put = maketriple(OC_CLRALSVARS); put->operand[0] = resptr; dqins(targchain.exorder.bl, exorder, put); advancewindow(); break; } } /* If we are doing alias processing, there are two possibilities: * 1) LHS is unsubscripted - it is an alias variable being created or replaced. Need to parse * the varname as if this were a regular set. * 2) LHS is subscripted - it is an alias container variable being created or replaced. The * processing here is to pass the base variable index to the store routine so bypass the * lvn() call. */ if (!alias_processing || TK_LPAREN == director_token) { /* Normal variable processing or we have a lh alias container */ if (!lvn(&v, OC_PUTINDX, 0)) SYNTAX_ERROR_NOREPORT_HERE; if (OC_PUTINDX == v.oprval.tref->opcode) { dqdel(v.oprval.tref, exorder); dqins(targchain.exorder.bl, exorder, v.oprval.tref); sub = v.oprval.tref; put_oc = OC_PUTINDX; if (TREF(temp_subs)) m_set_create_temporaries(sub, put_oc); } } else { /* Have alias variable. Argument is index into var table rather than pointer to var */ have_lh_alias = TRUE; /* We only want the variable index in this case. Since the entire hash structure to which * this variable is going to be pointing to is changing, doing anything that calls fetch() * is somewhat pointless so we avoid it by just accessing the variable information * directly. */ mvarptr = get_mvaddr(&window_ident); v = put_ilit(mvarptr->mvidx); advancewindow(); } /* Determine correct storing triple */ put = maketriple((!alias_processing ? OC_STO : (have_lh_alias ? OC_SETALS2ALS : OC_SETALSIN2ALSCT))); put->operand[0] = v; put->operand[1] = resptr; dqins(targchain.exorder.bl, exorder, put); break; case TK_CIRCUMFLEX: if (alias_processing) SYNTAX_ERROR(ERR_ALIASEXPECTED); s1 = curtchain->exorder.bl; if (!gvn()) SYNTAX_ERROR_NOREPORT_HERE; for (sub = curtchain->exorder.bl; sub != s1; sub = sub->exorder.bl) { put_oc = sub->opcode; if (OC_GVNAME == put_oc || OC_GVNAKED == put_oc || OC_GVEXTNAM == put_oc) break; } assert(OC_GVNAME == put_oc || OC_GVNAKED == put_oc || OC_GVEXTNAM == put_oc); dqdel(sub, exorder); dqins(targchain.exorder.bl, exorder, sub); if (TREF(temp_subs)) m_set_create_temporaries(sub, put_oc); put = maketriple(OC_GVPUT); put->operand[0] = resptr; dqins(targchain.exorder.bl, exorder, put); break; case TK_ATSIGN: if (alias_processing) SYNTAX_ERROR(ERR_ALIASEXPECTED); if (!indirection(&v)) SYNTAX_ERROR_NOREPORT_HERE; if (!got_lparen && TK_EQUAL != window_token) { assert(!curtchain_switched); put = newtriple(OC_COMMARG); put->operand[0] = v; put->operand[1] = put_ilit(indir_set); return TRUE; } put = maketriple(OC_INDSET); put->operand[0] = v; put->operand[1] = resptr; dqins(targchain.exorder.bl, exorder, put); break; case TK_DOLLAR: if (alias_processing) SYNTAX_ERROR(ERR_ALIASEXPECTED); advancewindow(); if (TK_IDENT != window_token) SYNTAX_ERROR(ERR_VAREXPECTED); if (TK_LPAREN != director_token) { /* Look for intrinsic special variables */ s1 = curtchain->exorder.bl; if (0 > (index = namelook(svn_index, svn_names, window_ident.addr, window_ident.len))) { STX_ERROR_WARN(ERR_INVSVN); /* sets "parse_warn" to TRUE */ } else if (!svn_data[index].can_set) { STX_ERROR_WARN(ERR_SVNOSET); /* sets "parse_warn" to TRUE */ } advancewindow(); if (!parse_warn) { if (SV_ETRAP != svn_data[index].opcode && SV_ZTRAP != svn_data[index].opcode) { /* Setting of $ZTRAP or $ETRAP must go through opp_svput because they * may affect the stack pointer. All others directly to op_svput(). */ put = maketriple(OC_SVPUT); } else put = maketriple(OC_PSVPUT); put->operand[0] = put_ilit(svn_data[index].opcode); put->operand[1] = resptr; dqins(targchain.exorder.bl, exorder, put); } else { /* OC_RTERROR triple would have been inserted in curtchain by ins_errtriple * (invoked by stx_error). To maintain consistency with the "if" portion of * this code, we need to move this triple to the "targchain". */ tmp = curtchain->exorder.bl; /* corresponds to put_ilit(FALSE) in ins_errtriple */ tmp = tmp->exorder.bl; /* corresponds to put_ilit(in_error) in ins_errtriple */ tmp = tmp->exorder.bl; /* corresponds to newtriple(OC_RTERROR) in ins_errtriple */ assert(OC_RTERROR == tmp->opcode); dqdel(tmp, exorder); dqins(targchain.exorder.bl, exorder, tmp); CHKTCHAIN(&targchain); } break; } /* Only 4 function names allowed on left side: $[Z]Piece and $[Z]Extract */ index = namelook(fun_index, fun_names, window_ident.addr, window_ident.len); if (0 > index) { STX_ERROR_WARN(ERR_INVFCN); /* sets "parse_warn" to TRUE */ /* OC_RTERROR triple would have been inserted in "curtchain" by ins_errtriple * (invoked by stx_error). We need to switch it to "targchain" to be consistent * with every other codepath in this module. */ tmp = curtchain->exorder.bl; /* corresponds to put_ilit(FALSE) in ins_errtriple */ tmp = tmp->exorder.bl; /* corresponds to put_ilit(in_error) in ins_errtriple */ tmp = tmp->exorder.bl; /* corresponds to newtriple(OC_RTERROR) in ins_errtriple */ assert(OC_RTERROR == tmp->opcode); dqdel(tmp, exorder); dqins(targchain.exorder.bl, exorder, tmp); CHKTCHAIN(&targchain); advancewindow(); /* skip past the function name */ advancewindow(); /* skip past the left paren */ /* Parse the remaining arguments until corresponding RIGHT-PAREN/SPACE/EOL is reached */ if (!parse_until_rparen_or_space()) SYNTAX_ERROR_NOREPORT_HERE; } else { switch(fun_data[index].opcode) { case OC_FNPIECE: setop = OC_SETPIECE; break; case OC_FNEXTRACT: is_extract = TRUE; setop = OC_SETEXTRACT; break; case OC_FNZPIECE: setop = OC_SETZPIECE; break; case OC_FNZEXTRACT: is_extract = TRUE; setop = OC_SETZEXTRACT; break; default: SYNTAX_ERROR(ERR_VAREXPECTED); } advancewindow(); advancewindow(); /* Although we see the get (target) variable first, we need to save it's processing * on another chain -- the targchain -- because the retrieval of the target is bypassed * and the naked indicator is not reset if the first/last parameters are not set in a * logical manner (must be > 0 and first <= last). So the evaluation order is * delimiter (if $piece), first, last, RHS of the set and then the target if applicable. * Set up primary action triple now since it is ref'd by the put triples generated below. */ s = maketriple(setop); /* Even for SET[Z]PIECE and SET[Z]EXTRACT, the SETxxxxx opcodes * do not do the final store, they only create the final value TO be * stored so generate the triples that will actually do the store now. * Note we are still building triples on the original curtchain. */ switch (window_token) { case TK_IDENT: if (!lvn(&v, OC_PUTINDX, 0)) SYNTAX_ERROR(ERR_VAREXPECTED); if (OC_PUTINDX == v.oprval.tref->opcode) { dqdel(v.oprval.tref, exorder); dqins(targchain.exorder.bl, exorder, v.oprval.tref); sub = v.oprval.tref; put_oc = OC_PUTINDX; if (TREF(temp_subs)) m_set_create_temporaries(sub, put_oc); } get = maketriple(OC_FNGET); get->operand[0] = v; put = maketriple(OC_STO); put->operand[0] = v; put->operand[1] = put_tref(s); break; case TK_ATSIGN: if (!indirection(&v)) SYNTAX_ERROR(ERR_VAREXPECTED); get = maketriple(OC_INDGET); get->operand[0] = v; get->operand[1] = put_str(0, 0); put = maketriple(OC_INDSET); put->operand[0] = v; put->operand[1] = put_tref(s); break; case TK_CIRCUMFLEX: s1 = curtchain->exorder.bl; if (!gvn()) SYNTAX_ERROR_NOREPORT_HERE; for (sub = curtchain->exorder.bl; sub != s1 ; sub = sub->exorder.bl) { put_oc = sub->opcode; if ((OC_GVNAME == put_oc) || (OC_GVNAKED == put_oc) || (OC_GVEXTNAM == put_oc)) break; } assert((OC_GVNAME == put_oc) || (OC_GVNAKED == put_oc) || (OC_GVEXTNAM == put_oc)); dqdel(sub, exorder); dqins(targchain.exorder.bl, exorder, sub); if (TREF(temp_subs)) m_set_create_temporaries(sub, put_oc); get = maketriple(OC_FNGVGET); get->operand[0] = put_str(0, 0); put = maketriple(OC_GVPUT); put->operand[0] = put_tref(s); break; default: SYNTAX_ERROR(ERR_VAREXPECTED); } s->operand[0] = put_tref(get); /* Code to fetch args for target triple are on targchain. Put get there now too. */ dqins(targchain.exorder.bl, exorder, get); CHKTCHAIN(&targchain); if (!is_extract) { /* Set $[z]piece */ delimiter = newtriple(OC_PARAMETER); s->operand[1] = put_tref(delimiter); first = newtriple(OC_PARAMETER); delimiter->operand[1] = put_tref(first); /* Process delimiter string ($[z]piece only) */ if (TK_COMMA != window_token) SYNTAX_ERROR(ERR_COMMA); advancewindow(); if (!strexpr(&delimval)) SYNTAX_ERROR_NOREPORT_HERE; assert(TRIP_REF == delimval.oprclass); } else { /* Set $[Z]Extract */ first = newtriple(OC_PARAMETER); s->operand[1] = put_tref(first); } /* Process first integer value */ if (window_token != TK_COMMA) firstval = put_ilit(1); else { advancewindow(); if (!intexpr(&firstval)) SYNTAX_ERROR(ERR_COMMA); assert(firstval.oprclass == TRIP_REF); } first->operand[0] = firstval; if (first_is_lit = (OC_ILIT == firstval.oprval.tref->opcode)) { assert(ILIT_REF ==firstval.oprval.tref->operand[0].oprclass); first_val_lit = firstval.oprval.tref->operand[0].oprval.ilit; } if (TK_COMMA != window_token) { /* There is no "last" value. Only if 1 char literal delimiter and * no "last" value can we generate shortcut code to op_set[z]p1 entry * instead of op_set[z]piece. Note if UTF8 mode is in effect, then this * optimization applies if the literal is one unicode char which may in * fact be up to 4 bytes but will still be passed as a single unsigned * integer. */ if (!is_extract) { delim_mval = &delimval.oprval.tref->operand[0].oprval.mlit->v; valid_char = TRUE; /* Basic assumption unles proven otherwise */ if (delimval.oprval.tref->opcode == OC_LIT && (1 == (gtm_utf8_mode ? MV_FORCE_LEN(delim_mval) : delim_mval->str.len))) { /* Single char delimiter for set $piece */ UNICODE_ONLY( if (gtm_utf8_mode) { /* We have a supposed single char delimiter but it * must be a valid utf8 char to be used by * op_setp1() and MV_FORCE_LEN won't tell us that. */ valid_char = UTF8_VALID(delim_mval->str.addr, (delim_mval->str.addr + delim_mval->str.len), delimlen); if (!valid_char && !badchar_inhibit) UTF8_BADCHAR(0, delim_mval->str.addr, (delim_mval->str.addr + delim_mval->str.len), 0, NULL); } ); if (valid_char || 1 == delim_mval->str.len) { /* This reference to a one character literal or a single * byte invalid utf8 character that needs to be turned into * an explict formated integer literal instead */ unichar.unichar_val = 0; if (!gtm_utf8_mode) { /* Single byte delimiter */ assert(1 == delim_mval->str.len); UNIX_ONLY(s->opcode = OC_SETZP1); VMS_ONLY(s->opcode = OC_SETP1); unichar.unibytes_val[0] = *delim_mval->str.addr; } UNICODE_ONLY( else { /* Potentially multiple bytes in one int */ assert(SIZEOF(int) >= delim_mval->str.len); memcpy(unichar.unibytes_val, delim_mval->str.addr, delim_mval->str.len); s->opcode = OC_SETP1; } ); delimlit = (mint)unichar.unichar_val; delimiter->operand[0] = put_ilit(delimlit); delim1char = TRUE; } } }
int m_zbreak(void) { triple *ref, *next; oprtype label, offset, routine, action, count; bool cancel, cancel_all, is_count, dummybool; error_def(ERR_LABELEXPECTED); error_def(ERR_RTNNAME); label = put_str((char *)&zero_ident.c[0], sizeof(mident)); cancel_all = FALSE; action = put_str("B", 1); if (window_token == TK_MINUS) { advancewindow(); cancel = TRUE; count = put_ilit((mint)CANCEL_ONE); } else { cancel = FALSE; count = put_ilit((mint)0); } if (window_token == TK_ASTERISK) { if (cancel) { advancewindow(); cancel_all = TRUE; if (!run_time) routine = put_str(&routine_name[0], sizeof(mident)); else routine = put_tref(newtriple(OC_CURRTN)); offset = put_ilit((mint) 0); count = put_ilit((mint) CANCEL_ALL); } else { stx_error(ERR_LABELEXPECTED); return FALSE; } } else { offset = put_ilit((mint) 0); if (!lref(&label,&offset, TRUE, indir_zbreak, !cancel, &dummybool)) return FALSE; if (label.oprclass == TRIP_REF && label.oprval.tref->opcode == OC_COMMARG) return TRUE; if (window_token != TK_CIRCUMFLEX) { if (!run_time) routine = put_str(&routine_name[0], sizeof(mident)); else routine = put_tref(newtriple(OC_CURRTN)); } else { advancewindow(); switch(window_token) { case TK_IDENT: routine = put_str(&window_ident.c[0], sizeof(mident)); advancewindow(); break; case TK_ATSIGN: if (!indirection(&routine)) return FALSE; break; default: stx_error(ERR_RTNNAME); return FALSE; } } if (!cancel && window_token == TK_COLON) { advancewindow(); if (window_token == TK_COLON) { is_count = TRUE; action = put_str("B",1); } else { if (!strexpr(&action)) return FALSE; is_count = window_token == TK_COLON; } if (is_count) { advancewindow(); if (!intexpr(&count)) return FALSE; } } } ref = newtriple(OC_SETZBRK); ref->operand[0] = label; next = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(next); next->operand[0] = offset; ref = newtriple(OC_PARAMETER); next->operand[1] = put_tref(ref); ref->operand[0] = routine; next = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(next); next->operand[0] = action; ref = newtriple(OC_PARAMETER); next->operand[1] = put_tref(ref); ref->operand[0] = count; return TRUE; }
int m_write(void) { error_def(ERR_STRINGOFLOW); oprtype x,*oprptr; mval lit; mstr *msp; int lnx; char *cp; triple *ref, *t1; triple *litlst[128], **llptr, **ptx, **ltop; llptr = litlst; ltop = 0; *llptr = 0; for (;;) { devctlexp = FALSE; switch(window_token) { case TK_ASTERISK: advancewindow(); if (!intexpr(&x)) return FALSE; assert(x.oprclass == TRIP_REF); ref = newtriple(OC_WTONE); ref->operand[0] = x; STO_LLPTR((x.oprval.tref->opcode == OC_ILIT) ? ref : 0); break; case TK_QUESTION: case TK_EXCLAIMATION: case TK_HASH: case TK_SLASH: if (!rwformat()) return FALSE; STO_LLPTR(0); break; default: switch (strexpr(&x)) { case EXPR_FAIL: return FALSE; case EXPR_GOOD: assert(x.oprclass == TRIP_REF); if (devctlexp) { ref = newtriple(OC_WRITE); ref->operand[0] = x; STO_LLPTR(0); } else if (x.oprval.tref->opcode == OC_CAT) { wrtcatopt(x.oprval.tref,&llptr,LITLST_TOP); } else { ref = newtriple(OC_WRITE); ref->operand[0] = x; STO_LLPTR((x.oprval.tref->opcode == OC_LIT) ? ref : 0); } break; case EXPR_INDR: make_commarg(&x,indir_write); STO_LLPTR(0); break; default: assert(FALSE); } break; } if (window_token != TK_COMMA) break; advancewindow(); if (llptr >= LITLST_TOP) { *++llptr = 0; ltop = llptr; llptr = 0; } } STO_LLPTR(0); if (ltop) llptr = ltop; for (ptx = litlst ; ptx < llptr ; ptx++) { if (*ptx && *(ptx + 1)) { lit.mvtype = MV_STR; lit.str.addr = cp = (char * ) stringpool.free; for (t1 = ref = *ptx++ ; ref ; ref = *ptx++) { if (ref->opcode == OC_WRITE) { msp = &(ref->operand[0].oprval.tref->operand[0].oprval.mlit->v.str); lnx = msp->len; if ( cp + lnx > (char *) stringpool.top) { stx_error(ERR_STRINGOFLOW); return FALSE; } memcpy(cp, msp->addr, lnx); cp += lnx; } else { assert(ref->opcode == OC_WTONE); if (cp + 1 > (char *) stringpool.top) { stx_error(ERR_STRINGOFLOW); return FALSE; } *cp++ = ref->operand[0].oprval.tref->operand[0].oprval.ilit; } ref->operand[0].oprval.tref->opcode = OC_NOOP; ref->opcode = OC_NOOP; ref->operand[0].oprval.tref->operand[0].oprclass = OC_NOOP; ref->operand[0].oprclass = 0; } ptx--; stringpool.free = (unsigned char *) cp; lit.str.len = INTCAST(cp - lit.str.addr); s2n(&lit); t1->opcode = OC_WRITE; t1->operand[0] = put_lit(&lit); } } return TRUE; }