📄 hooks.c
字号:
if ( ! Conjunct() ) FailSyn("expression"); while ( Find("or") ) { BN += 2; if ( ! Conjunct() ) FailSyn("expression"); DumpOp(OP_OR, Fi); } return true;}Boolean Conjunct()/* -------- */{ int Fi=BN; if ( ! SExpression() ) FailSyn("expression"); while ( Find("and") ) { BN += 3; if ( ! SExpression() ) FailSyn("expression"); DumpOp(OP_AND, Fi); } return true;}String RelOps[] = {">=", "<=", "!=", "<>", ">", "<", "=", (String) 0};Boolean SExpression()/* ----------- */{ int o, Fi=BN; if ( ! AExpression() ) FailSyn("expression"); if ( (o = FindOne(RelOps)) >= 0 ) { BN += strlen(RelOps[o]); if ( ! AExpression() ) FailSyn("expression"); DumpOp(( o == 0 ? OP_GE : o == 1 ? OP_LE : o == 4 ? OP_GT : o == 5 ? OP_LT : o == 2 || o == 3 ? ( TStack[TSN-1].Type == 'S' ? OP_SNE : OP_NE ) : ( TStack[TSN-1].Type == 'S' ? OP_SEQ : OP_EQ ) ), Fi); } return true;}String AddOps[] = {"+", "-", (String) 0};Boolean AExpression()/* ----------- */{ int o, Fi=BN; if ( Buff[BN] == ' ' ) BN++; if ( (o = FindOne(AddOps)) >= 0 ) { BN += 1; } if ( ! Term() ) FailSyn("expression"); if ( o == 1 ) DumpOp(OP_UMINUS, Fi); while ( (o = FindOne(AddOps)) >= 0 ) { BN += 1; if ( ! Term() ) FailSyn("arithmetic expression"); DumpOp((char)(OP_PLUS + o), Fi); } return true;}String MultOps[] = {"*", "/", "%", (String) 0};Boolean Term()/* ---- */{ int o, Fi=BN; if ( ! Factor() ) FailSyn("expression"); while ( (o = FindOne(MultOps)) >= 0 ) { BN += 1; if ( ! Factor() ) FailSyn("arithmetic expression"); DumpOp((char)(OP_MULT + o), Fi); } return true;}Boolean Factor()/* ---- */{ int Fi=BN; if ( ! Primary() ) FailSyn("value"); while ( Find("^") ) { BN += 1; if ( ! Primary() ) FailSyn("exponent"); DumpOp(OP_POW, Fi); } return true;}Boolean Primary()/* ------- */{ if ( Atom() ) { return true; } else if ( Find("(") ) { BN++; if ( ! Expression() ) FailSyn("expression in parentheses"); if ( ! Find(")") ) FailSyn("')'"); BN++; return true; } else { FailSyn("attribute, value, or '('"); }}String Funcs[] = {"sin", "cos", "tan", "log", "exp", "int", (String) 0};Boolean Atom()/* ---- */{ char *EndPtr, *Str, Date[11], Time[9]; int o, FirstBN, Fi=BN; ContValue F; Attribute Att; if ( Buff[BN] == ' ' ) BN++; if ( Buff[BN] == '"' ) { FirstBN = ++BN; while ( Buff[BN] != '"' ) { if ( ! Buff[BN] ) FailSyn("closing '\"'"); BN++; } /* Make a copy of the string without double quotes */ Buff[BN] = '\00'; Str = strdup(Buff + FirstBN); Buff[BN++] = '"'; Dump(OP_STR, 0, Str, Fi); } else if ( (Att = FindAttName()) ) { BN += strlen(AttName[Att]); Dump(OP_ATT, 0, (String) (long) Att, Fi); } else if ( isdigit(Buff[BN]) ) { /* Check for date or time first */ if ( ( Buff[BN+4] == '/' && Buff[BN+7] == '/' || Buff[BN+4] == '-' && Buff[BN+7] == '-' )&& isdigit(Buff[BN+1]) && isdigit(Buff[BN+2]) && isdigit(Buff[BN+3]) && isdigit(Buff[BN+5]) && isdigit(Buff[BN+6]) && isdigit(Buff[BN+8]) && isdigit(Buff[BN+9]) ) { memcpy(Date, Buff+BN, 10); Date[10] = '\00'; if ( (F = DateToDay(Date)) == 0 ) { Error(BADDEF1, Date, "date"); } BN += 10; } else if ( Buff[BN+2] == ':' && Buff[BN+5] == ':' && isdigit(Buff[BN+1]) && isdigit(Buff[BN+3]) && isdigit(Buff[BN+4]) && isdigit(Buff[BN+6]) && isdigit(Buff[BN+7]) ) { memcpy(Time, Buff+BN, 8); Time[8] = '\00'; if ( (F = TimeToSecs(Time)) == 0 ) { Error(BADDEF1, Time, "time"); } BN += 8; } else { F = strtod(Buff+BN, &EndPtr); /* Check for period after integer */ if ( EndPtr > Buff+BN+1 && *(EndPtr-1) == '.' ) { EndPtr--; } BN = EndPtr - Buff; } Dump(OP_NUM, F, Nil, Fi); } else if ( (o = FindOne(Funcs)) >= 0 ) { BN += 3; if ( ! Find("(") ) FailSyn("'(' after function name"); BN++; if ( ! Expression() ) FailSyn("expression"); if ( ! Find(")") ) FailSyn("')' after function argument"); BN++; DumpOp((char)(OP_SIN + o), Fi); } else if ( Buff[BN] == '?' ) { BN++; if ( TStack[TSN-1].Type == 'N' ) { Dump(OP_NUM, _UNK.cval, Nil, Fi); } else { Dump(OP_STR, 0, Nil, Fi); } } else if ( ! memcmp(Buff+BN, "N/A", 3) ) { BN += 3; if ( TStack[TSN-1].Type == 'N' ) { Dump(OP_NUM, _NA.cval, Nil, Fi); } else { Dump(OP_STR, 0, strdup("N/A"), Fi); } } else { return false; } return true;}/*************************************************************************//* *//* Skip spaces and check for specific string *//* *//*************************************************************************/Boolean Find(String S)/* ---- */{ if ( Buff[BN] == ' ' ) BN++; return ( ! Buff[BN] ? false : ! memcmp(Buff+BN, S, strlen(S)) );}/*************************************************************************//* *//* Find one of a zero-terminated list of alternatives *//* *//*************************************************************************/int FindOne(String *Alt)/* ------- */{ int a; for ( a = 0 ; Alt[a] ; a++ ) { if ( Find(Alt[a]) ) return a; } return -1;}/*************************************************************************//* *//* Find an attribute name *//* *//*************************************************************************/Attribute FindAttName()/* ----------- */{ Attribute Att, LongestAtt=0; ForEach(Att, 1, MaxAtt-1) { if ( ! Exclude(Att) && Find(AttName[Att]) ) { if ( ! LongestAtt || strlen(AttName[Att]) > strlen(AttName[LongestAtt]) ) { LongestAtt = Att; } } } return LongestAtt;}/*************************************************************************//* *//* Error message routines. Syntax errors come from the *//* recursive descent parser, semantics errors from the routines *//* that build up the equivalent polish *//* *//*************************************************************************/void DefSyntaxError(String Msg)/* -------------- */{ String RestOfText; int i=10; if ( ! PreviousError ) { RestOfText = Buff + BN; /* Abbreviate text if longer than 12 characters */ if ( CharWidth(RestOfText) > 12 ) {#ifdef UTF8 /* Find beginning of UTF-8 character */ for ( ; (RestOfText[i] & 0x80) ; i++) ;#endif RestOfText[i] = RestOfText[i+1] = '.'; } Error(BADDEF1, RestOfText, Msg); PreviousError = true; }}void DefSemanticsError(int Fi, String Msg, int OpCode)/* ----------------- */{ char Exp[1000], XMsg[1000], Op[1000]; if ( ! PreviousError ) { /* Abbreviate the input if necessary */ if ( BN - Fi > 23 ) { sprintf(Exp, "%.10s...%.10s", Buff+Fi, Buff+BN-10); } else { sprintf(Exp, "%.*s", BN - Fi, Buff+Fi); } switch ( OpCode ) { case OP_AND: sprintf(Op, "%s", "and"); break; case OP_OR: sprintf(Op, "%s", "or"); break; case OP_SEQ: case OP_EQ: sprintf(Op, "%s", "="); break; case OP_SNE: case OP_NE: sprintf(Op, "%s", "<>"); break; case OP_GT: sprintf(Op, "%s", ">"); break; case OP_GE: sprintf(Op, "%s", ">="); break; case OP_LT: sprintf(Op, "%s", "<"); break; case OP_LE: sprintf(Op, "%s", "<="); break; case OP_PLUS: sprintf(Op, "%s", "+"); break; case OP_MINUS: sprintf(Op, "%s", "-"); break; case OP_UMINUS: sprintf(Op, "%s", "unary -"); break; case OP_MULT: sprintf(Op, "%s", "*"); break; case OP_DIV: sprintf(Op, "%s", "/"); break; case OP_MOD: sprintf(Op, "%s", "%"); break; case OP_POW: sprintf(Op, "%s", "^"); break; case OP_SIN: sprintf(Op, "%s", "sin"); break; case OP_COS: sprintf(Op, "%s", "cos"); break; case OP_TAN: sprintf(Op, "%s", "tan"); break; case OP_LOG: sprintf(Op, "%s", "log"); break; case OP_EXP: sprintf(Op, "%s", "exp"); break; case OP_INT: sprintf(Op, "%s", "int"); } sprintf(XMsg, "%s with '%s'", Msg, Op); Error(BADDEF2, Exp, XMsg); PreviousError = true; }}/*************************************************************************//* *//* Reverse polish routines. These use a model of the stack *//* during expression evaluation to detect type conflicts etc *//* *//*************************************************************************/void Dump(char OpCode, ContValue F, String S, int Fi)/* ---- */{ if ( Buff[Fi] == ' ' ) Fi++; if ( ! UpdateTStack(OpCode, F, S, Fi) ) return; /* Make sure enough room for this element */ if ( DN >= DefSize-1 ) { Realloc(AttDef[MaxAtt], DefSize += 100, DefElt); } DefOp(AttDef[MaxAtt][DN]) = OpCode; if ( OpCode == OP_ATT || OpCode == OP_STR ) { DefSVal(AttDef[MaxAtt][DN]) = S; } else { DefNVal(AttDef[MaxAtt][DN]) = F; } DN++;}void DumpOp(char OpCode, int Fi)/* ------ */{ Dump(OpCode, 0, Nil, Fi);}Boolean UpdateTStack(char OpCode, ContValue F, String S, int Fi)/* ------------ */{ if ( TSN >= TStackSize ) { Realloc(TStack, TStackSize += 50, EltRec); } switch ( OpCode ) { case OP_ATT: TStack[TSN].Type = ( Continuous((long) S) ? 'N' : 'S' ); break; case OP_NUM: TStack[TSN].Type = 'N'; break; case OP_STR: TStack[TSN].Type = 'S'; break; case OP_AND: case OP_OR: if ( TStack[TSN-2].Type != 'B' || TStack[TSN-1].Type != 'B' ) { FailSem("non-logical value"); } TSN -= 2; break; case OP_EQ: case OP_NE: if ( TStack[TSN-2].Type != TStack[TSN-1].Type ) { FailSem("incompatible values"); } TSN -= 2; TStack[TSN].Type = 'B'; break; case OP_GT: case OP_GE: case OP_LT: case OP_LE: if ( TStack[TSN-2].Type != 'N' || TStack[TSN-1].Type != 'N' ) { FailSem("non-arithmetic value"); } TSN -= 2; TStack[TSN].Type = 'B'; break; case OP_SEQ: case OP_SNE: if ( TStack[TSN-2].Type != 'S' || TStack[TSN-1].Type != 'S' ) { FailSem("incompatible values"); } TSN -= 2; TStack[TSN].Type = 'B'; break; case OP_PLUS: case OP_MINUS: case OP_MULT: case OP_DIV: case OP_MOD: case OP_POW: if ( TStack[TSN-2].Type != 'N' || TStack[TSN-1].Type != 'N' ) { FailSem("non-arithmetic value"); } TSN -= 2; break; case OP_UMINUS: if ( TStack[TSN-1].Type != 'N' ) { FailSem("non-arithmetic value"); } TSN--; break; case OP_SIN: case OP_COS: case OP_TAN: case OP_LOG: case OP_EXP: case OP_INT: if ( TStack[TSN-1].Type != 'N' ) { FailSem("non-arithmetic argument"); } TSN--; } TStack[TSN].Fi = Fi; TStack[TSN].Li = BN-1; TSN++; return true;}/*************************************************************************//* *//* Evaluate an implicit attribute for a case *//* *//*************************************************************************/#define Unknown(c,a) (! DVal(c,a))#define CUnknownVal(AV) (AV.cval==UNKNOWN)#define DUnknownVal(AV) (! AV.dval)#define DUNA(a) (DUnknownVal(XStack[a]) || NotApplicVal(XStack[a]))#define CUNA(a) (CUnknownVal(XStack[a]) || NotApplicVal(XStack[a]))#define C1(x) (CUNA(XSN-1) ? _UNK.cval : (x))#define C2(x) (CUNA(XSN-1) || CUNA(XSN-2) ? _UNK.cval : (x))#define CD2(x) (CUNA(XSN-1) || CUNA(XSN-2) ? 0 : (x))#define D2(x) (DUNA(XSN-1) || DUNA(XSN-2) ? 0 : (x))AttValue EvaluateDef(Definition D, Description Case)/* ----------- */{ XStackElt XStack[100]; /* allows 100-level nesting */ int XSN=0, DN, bv1, bv2, Mult; double cv1, cv2; String sv1, sv2; Attribute Att; DefElt DElt; AttValue ReturnVal; for ( DN = 0 ; ; DN++) { switch ( DefOp((DElt = D[DN])) ) { case OP_ATT: Att = (long) DefSVal(DElt);#if defined PREDICT || defined SEE5 && defined WIN32 && ! defined _CONSOLE GetValue(Att);#endif if ( Continuous(Att) ) { XStack[XSN++].cval = CVal(Case, Att); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -