/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* $Header: b2exp.c,v 1.4 85/08/22 16:54:36 timo Exp $ */ #include "b.h" #include "b1obj.h" #include "b2par.h" #include "b2syn.h" #include "b2nod.h" #include "b2exp.h" #include "b3err.h" /* ******************************************************************** */ /* expression */ /* ******************************************************************** */ Visible parsetree expr(q) txptr q; { return collateral(q, singexpr); } Forward parsetree rsingexpr(); Visible parsetree singexpr(q) txptr q; { if (nothing(q, "expression")) return NilTree; else { expadm adm; initexp(&adm); return rsingexpr(q, &adm); } } Hidden Procedure initexp(adm) expadm *adm; { Parsed(adm)= Yes; N_fld(adm)= 0; Prop(adm)= dya_proposition; dya_proposition= No; } Hidden bool expr_opr() { return reptext_sign() || center_sign() || leftadj_sign() || rightadj_sign(); } Forward parsetree term(), factor(), primary(), base(), unp_expr(); Forward bool element(); Hidden parsetree rsingexpr(q, adm) txptr q; expadm *adm; { parsetree v; value w; txptr tx0= tx; v= term(q, adm); skipsp(&tx); if (Parsed(adm) && Text(q) && expr_opr()) { if (nodetype(v) == DYAF) pprerr(Prio); dya_formula(q, adm, &v, mk_text(textsign), L_expr, base); } skipsp(&tx); if (Parsed(adm) && Prop(adm)) { if (Text(q) && (nodetype(v) == DYAF || Level(adm) < L_expr)) /* predicate must follow */ return v; else if (Text(q) && tag_operator(q, &w)) dya_formula(q, adm, &v, w, L_expr, unp_expr); else parerr(MESS(2100, "no test where expected")); } if (Parsed(adm) && Text(q) && tag_operator(q, &w)) { if (nodetype(v) == DYAF) pprerr(Prio); dya_formula(q, adm, &v, w, L_expr, base); } if (!Parsed(adm)) /* v is an UNPARSED node */ *Branch(v, UNP_TEXT)= cr_text(tx0, tx); upto_expr(q); return v; } Hidden Procedure dya_formula(q, adm, v, name, lev, fct) txptr q; expadm *adm; parsetree *v, (*fct)(); value name; intlet lev; { parsetree w; if (Level(adm) < lev) pprerr(Prio); N_fld(adm)+= 2; w= (*fct)(q, adm); if (Parsed(adm)) { N_fld(adm)-= 2; if (Trim(adm)) *v= node3(b_behead(name) ? BEHEAD : CURTAIL, *v, w); else *v= node5(DYAF, *v, name, w, Vnil); } else { *Field(Unp_comp(adm), --N_fld(adm))= name; *Field(Unp_comp(adm), --N_fld(adm))= *v; *v= w; } } /* ******************************************************************** */ /* term */ /* ******************************************************************** */ Hidden bool term_opr() { return plus_sign() || minus_sign() || join_sign(); } Hidden parsetree term(q, adm) txptr q; expadm *adm; { parsetree v= factor(q, adm); skipsp(&tx); while (Parsed(adm) && Text(q) && term_opr()) { dya_formula(q, adm, &v, mk_text(textsign), L_term, factor); skipsp(&tx); } return v; } /* ******************************************************************** */ /* factor */ /* ******************************************************************** */ Hidden parsetree factor(q, adm) txptr q; expadm *adm; { parsetree v= primary(q, adm); skipsp(&tx); while (Parsed(adm) && Text(q) && times_sign()) { dya_formula(q, adm, &v, mk_text(textsign), L_factor, primary); skipsp(&tx); } if (Parsed(adm) && Text(q) && over_sign()) dya_formula(q, adm, &v, mk_text(textsign), L_factor, primary); return v; } /* ******************************************************************** */ /* primary */ /* ******************************************************************** */ Hidden parsetree primary(q, adm) txptr q; expadm *adm; { parsetree v; v= base(q, adm); skipsp(&tx); if (Parsed(adm) && Text(q) && number_sign()) dya_formula(q, adm, &v, mk_text(textsign), L_number, base); skipsp(&tx); if (Parsed(adm) && Text(q) && power_sign()) dya_formula(q, adm, &v, mk_text(textsign), L_power, base); return v; } /* ******************************************************************** */ /* base */ /* ******************************************************************** */ Forward parsetree rbase(); Hidden parsetree base(q, adm) txptr q; expadm *adm; { State(adm)= S_else; Level(adm)= L_expr; Trim(adm)= No; return rbase(q, adm); } Hidden bool critical(adm, v) expadm *adm; value v; { if (State(adm) == S_t) { if (b_plus(v) || b_minus(v)) return Level(adm) >= L_term; if (b_number(v)) return Level(adm) >= L_number; } return No; } Hidden parsetree mon_formula(q, adm, w, fct) txptr q; expadm *adm; value w; parsetree (*fct)(); { parsetree v; N_fld(adm)++; v= (*fct)(q, adm); if (Parsed(adm)) { N_fld(adm)--; return v == NilTree ? node2(TAG, w) : node4(MONF, w, v, Vnil); } else { *Field(Unp_comp(adm), --N_fld(adm))= w; return v; } } Hidden Procedure adjust_level(adm, lev) expadm *adm; intlet lev; { if (lev < Level(adm)) Level(adm)= lev; } Hidden parsetree rbase(q, adm) txptr q; expadm *adm; { parsetree v; value name; skipsp(&tx); if (Text(q) && tag_operator(q, &name)) { if (State(adm) == S_tt) return mon_formula(q, adm, name, unp_expr); if (State(adm) == S_t) { if (Level(adm) == L_expr || Prop(adm)) State(adm)= S_tt; else if (!Trim(adm)) adjust_level(adm, L_bottom); } else State(adm)= S_t; v= mon_formula(q, adm, name, rbase); if (!Trim(adm) && Parsed(adm) && nodetype(v) == MONF) adjust_level(adm, L_bottom); return v; } else if (Text(q) && (dyamon_sign() || mon_sign())) { name= mk_text(textsign); if (State(adm) == S_tt || critical(adm, name)) return mon_formula(q, adm, name, unp_expr); if (!Trim(adm)) { if (State(adm) == S_t) adjust_level(adm, L_bottom); else if (b_minus(name)) adjust_level(adm, L_factor); else if (b_number(name)) adjust_level(adm, L_number); else if (b_numtor(name) || b_denomtor(name)) adjust_level(adm, L_bottom); } State(adm)= S_else; if (!Trim(adm) && b_minus(name)) { intlet lev= Level(adm); v= mon_formula(q, adm, name, primary); adjust_level(adm, lev); return v; } else return mon_formula(q, adm, name, rbase); } else if (Text(q) && element(q, &v)) { if (State(adm) == S_tt) return mon_formula(q, adm, v, unp_expr); exp_trimmed_text(q, adm, &v); return v; } else { if (State(adm) == S_else) parerr(MESS(2101, "no expression where expected")); return NilTree; } } /* ******************************************************************** */ /* element */ /* ******************************************************************** */ Forward bool closed_expr(), constant(), text_dis(), tlr_dis(), seltrim_tag(); Hidden bool element(q, v) txptr q; parsetree *v; { if (seltrim_tag(q, v) || closed_expr(q, v) || constant(q, v) || text_dis(q, v) || tlr_dis(q, v) ) { selection(q, v); return Yes; } return No; } /* ******************************************************************** */ /* (seltrim_tag) */ /* ******************************************************************** */ Hidden bool seltrim_tag(q, v) txptr q; parsetree *v; { value name; txptr tx0= tx; if (Text(q) && is_tag(&name)) { txptr tx1= tx; skipsp(&tx); if (Text(q) && (sub_sign() || trim_sign())) { tx= tx1; *v= node2(TAG, name); return Yes; } else { release(name); tx= tx0; } } return No; } /* ******************************************************************** */ /* (expression) */ /* ******************************************************************** */ Hidden bool closed_expr(q, v) txptr q; parsetree *v; { return open_sign() ? (*v= compound(q, expr), Yes) : No; } /* ******************************************************************** */ /* constant */ /* */ /* note: stand_alone E not allowed */ /* ******************************************************************** */ Forward bool digits(); Hidden bool constant(q, v) txptr q; parsetree *v; { if (Dig(Char(tx)) || Char(tx) == '.') { txptr tx0= tx; bool d= digits(q); if (Text(q) && point_sign() && !digits(q) && !d) pprerr(MESS(2102, "point without digits")); if (Text(q) && Char(tx) == 'E' && (Dig(Char(tx+1)) || !keymark(Char(tx+1))) ) { tx++; if (Text(q) && (plus_sign() || minus_sign())); if (!digits(q)) pprerr(MESS(2103, "E not followed by exponent")); } *v= node3(NUMBER, numconst(tx0, tx), cr_text(tx0, tx)); return Yes; } return No; } Hidden bool digits(q) txptr q; { txptr tx0= tx; while (Text(q) && Dig(Char(tx))) tx++; return tx > tx0; } /* ******************************************************************** */ /* textual_display */ /* ******************************************************************** */ Forward parsetree text_body(); Hidden bool text_dis(q, v) txptr q; parsetree *v; { if (apostrophe_sign() || quote_sign()) { parsetree w; value aq= mk_text(textsign); w= text_body(q, textsign); if (w == NilTree) w= node3(TEXT_LIT, mk_text(""), NilTree); *v= node3(TEXT_DIS, aq, w); return Yes; } return No; } Forward bool is_conversion(); Hidden parsetree text_body(q, aq) txptr q; string aq; { value head; parsetree tail; txptr tx0= tx; while (Text(q)) { if (Char(tx) == *aq || Char(tx) == '`') { head= tx0 < tx ? cr_text(tx0, tx) : Vnil; if (Char(tx) == Char(tx+1)) { value spec= cr_text(tx, tx+1); tx+= 2; tail= text_body(q, aq); tail= node3(TEXT_LIT, spec, tail); } else { parsetree e; if (is_conversion(q, &e)) { tail= text_body(q, aq); tail= node3(TEXT_CONV, e, tail); } else { tx++; tail= NilTree; } } if (head == Vnil) return tail; else return node3(TEXT_LIT, head, tail); } else tx++; } parerr2(MESS(2104, "cannot find matching "), MESSMAKE(aq)); return NilTree; } Hidden bool is_conversion(q, v) txptr q; parsetree *v; { if (conv_sign()) { txptr ftx, ttx; req("`", q, &ftx, &ttx); *v= expr(ftx); tx= ttx; return Yes; } return No; } /* ******************************************************************** */ /* table_display; list_display; range_display; */ /* ******************************************************************** */ Hidden bool elt_dis(v) parsetree *v; { if (curlyclose_sign()) { *v= node1(ELT_DIS); return Yes; } return No; } Hidden bool range_dis(q, v) txptr q; parsetree *v; { txptr ftx, ttx; if (find("..", q, &ftx, &ttx)) { parsetree w; if (Char(ttx) == '.') { ftx++; ttx++; } w= singexpr(ftx); tx= ttx; *v= node3(RANGE_DIS, w, singexpr(q)); return Yes; } return No; } Forward value tab_comp(); Hidden bool tab_dis(q, v) txptr q; parsetree *v; { if (Char(tx) == '[') { *v= node2(TAB_DIS, tab_comp(q, 1)); return Yes; } return No; } Hidden value tab_comp(q, n) txptr q; intlet n; { value v; parsetree key, assoc; txptr ftx, ttx; if (find(";", q, &ftx, &ttx)) { tab_elem(ftx, &key, &assoc); tx= ttx; v= tab_comp(q, n+2); } else { tab_elem(q, &key, &assoc); v= mk_compound(n+1); } *Field(v, n-1)= key; *Field(v, n)= assoc; return v; } Hidden Procedure tab_elem(q, key, assoc) txptr q; parsetree *key, *assoc; { txptr ftx, ttx; need("["); req("]", q, &ftx, &ttx); *key= expr(ftx); tx= ttx; need(":"); *assoc= singexpr(q); } Forward value list_comp(); Hidden Procedure list_dis(q, v) txptr q; parsetree *v; { *v= node2(LIST_DIS, list_comp(q, 1)); } Hidden value list_comp(q, n) txptr q; intlet n; { value v; parsetree w; txptr ftx, ttx; if (find(";", q, &ftx, &ttx)) { w= singexpr(ftx); tx= ttx; v= list_comp(q, n+1); } else { w= singexpr(q); v= mk_compound(n); } *Field(v, n-1)= w; return v; } Hidden bool tlr_dis(q, v) txptr q; parsetree *v; { if (curlyopen_sign()) { skipsp(&tx); if (!elt_dis(v)) { txptr ftx, ttx; req("}", q, &ftx, &ttx); if (!range_dis(ftx, v)) { skipsp(&tx); if (!tab_dis(ftx, v)) list_dis(ftx, v); } tx= ttx; } return Yes; } return No; } /* ******************************************************************** */ /* selection */ /* ******************************************************************** */ Visible Procedure selection(q, v) txptr q; parsetree *v; { txptr ftx, ttx; skipsp(&tx); while (Text(q) && sub_sign()) { req("]", q, &ftx, &ttx); *v= node3(SELECTION, *v, expr(ftx)); tx= ttx; skipsp(&tx); } } /* ******************************************************************** */ /* trimmed_text */ /* ******************************************************************** */ Hidden bool is_trimmed_text(q) txptr q; { txptr tx0= tx; bool b; skipsp(&tx); b= Text(q) && trim_sign(); tx= tx0; return b; } Hidden Procedure trimmed_text(q, adm, v) txptr q; expadm *adm; parsetree *v; { Trim(adm)= Yes; while (Parsed(adm) && Text(q) && trim_sign()) { State(adm)= S_else; dya_formula(q, adm, v, mk_text(textsign), L_bottom, rbase); skipsp(&tx); } Trim(adm)= No; } Visible Procedure tar_trimmed_text(q, v) txptr q; parsetree *v; { if (is_trimmed_text(q)) { expadm adm; initexp(&adm); Level(&adm)= L_bottom; trimmed_text(q, &adm, v); } } Hidden Procedure exp_trimmed_text(q, adm, v) txptr q; expadm *adm; parsetree *v; { if (!Trim(adm) && is_trimmed_text(q)) { intlet s= State(adm); /* save */ if (State(adm) == S_t) adjust_level(adm, L_bottom); trimmed_text(q, adm, v); State(adm)= s; /* restore */ } } /* ******************************************************************** */ /* unp_expr, unp_test */ /* ******************************************************************** */ Forward bool item(); Hidden parsetree unp_expr(q, adm) txptr q; expadm *adm; { value v; skipsp(&tx); if (Text(q) && item(q, &v)) { return mon_formula(q, adm, v, unp_expr); } else { Parsed(adm)= No; Unp_comp(adm)= mk_compound(N_fld(adm)); return node3(UNPARSED, Unp_comp(adm), Vnil); } } Visible parsetree unp_test(q) txptr q; { parsetree v; expadm adm; txptr tx0= tx; initexp(&adm); v= unp_expr(q, &adm); *Branch(v, UNP_TEXT)= cr_text(tx0, tx); return v; } Visible bool tag_operator(q, v) txptr q; value *v; { txptr tx0= tx; if (Text(q) && is_tag(v)) { skipsp(&tx); if (!(Text(q) && (sub_sign() || trim_sign()))) return Yes; else { release(*v); tx= tx0; } } return No; } Hidden bool dm_operator(q, v) txptr q; value *v; { return dyamon_sign() ? (*v= mk_text(textsign), Yes) : tag_operator(q, v); } Hidden bool d_operator(q, v) txptr q; value *v; { return dya_sign() ? (*v= mk_text(textsign), Yes) : dm_operator(q, v); } Hidden bool m_operator(q, v) txptr q; value *v; { return mon_sign() ? (*v= mk_text(textsign), Yes) : dm_operator(q, v); } Hidden bool trim_operator(q, v) txptr q; value *v; { return trim_sign() ? (*v= mk_text(textsign), Yes) : No; } Hidden bool item(q, v) txptr q; value *v; { return tag_operator(q, v) || trim_operator(q, v) || d_operator(q, v) || m_operator(q, v) || element(q, v); } /* ******************************************************************** */ /* upto_expr */ /* ******************************************************************** */ Hidden Procedure upto_expr(q) txptr q; { skipsp(&tx); if (Text(q)) { value dum; if (d_operator(q, &dum)) { release(dum); pprerr(Prio); } else parerr(MESS(2105, "something unexpected following expression")); tx= q; } } /* ******************************************************************** */ Hidden bool is_opr(v, s) value v; string s; { value t= Vnil; bool is= Is_text(v) && compare(v, t= mk_text(s)) == 0; release(t); return is; } Visible bool b_about(v) value v; { return is_opr(v, "~"); } Visible bool b_numtor(v) value v; { return is_opr(v, "*/"); } Visible bool b_denomtor(v) value v; { return is_opr(v, "/*"); } Visible bool b_plus(v) value v; { return is_opr(v, "+"); } Visible bool b_minus(v) value v; { return is_opr(v, "-"); } Visible bool b_number(v) value v; { return is_opr(v, "#"); } Visible bool b_behead(v) value v; { return is_opr(v, "@"); } Visible bool b_curtail(v) value v; { return is_opr(v, "|"); } #ifdef NOT_USED Visible bool b_times(v) value v; { return is_opr(v, "*"); } Visible bool b_over(v) value v; { return is_opr(v, "/"); } Visible bool b_power(v) value v; { return is_opr(v, "**"); } Visible bool b_join(v) value v; { return is_opr(v, "^"); } Visible bool b_reptext(v) value v; { return is_opr(v, "^^"); } Visible bool b_center(v) value v; { return is_opr(v, "><"); } Visible bool b_leftadj(v) value v; { return is_opr(v, "<<"); } Visible bool b_rightadj(v) value v; { return is_opr(v, ">>"); } #endif