00001
00002
00003
00004 #include <stdlib.h>
00005 #include "utils.h"
00006 #include "parser.h"
00007 #include "rules.h"
00008 #include "functions.h"
00009 #include "configuration.h"
00010 #include "filesystem.h"
00011
00012 Op new_ops[num_ops] = {
00013 {"-",1,10},
00014 {"++",2,6},
00015 {"+",2,6},
00016 {"-",2,6},
00017 {"*",2,7},
00018 {"/",2,7},
00019 {"&&",2,3},
00020 {"%%",2,2},
00021 {"||",2,2},
00022 {"%",2,7},
00023 {"<=",2,5},
00024 {">=",2,5},
00025 {"<",2,5},
00026 {">",2,5},
00027 {"==",2,4},
00028 {"!=",2,4},
00029 {"!",1,10},
00030 {"like regex",2,4},
00031 {"not like regex",2,4},
00032 {"like",2,4},
00033 {"not like",2,4},
00034 {"^^",2,8},
00035 {"^",2,8},
00036 {"floor",1,10},
00037 {"ceiling",1,10},
00038 {"log",1,10},
00039 {"exp",1,10},
00040 {"abs",1,10},
00041 {"=",2,1},
00042 {"@@",2,20}
00043 };
00044 PARSER_FUNC_PROTO2(Term, int rulegen, int prec);
00045 PARSER_FUNC_PROTO2(Actions, int rulegen, int backwardCompatible);
00046 PARSER_FUNC_PROTO1(T, int rulegen);
00047 PARSER_FUNC_PROTO1(Value, int rulegen);
00048 PARSER_FUNC_PROTO1(StringExpression, Token *tk);
00049 PARSER_FUNC_PROTO(RuleName);
00050 PARSER_FUNC_PROTO(TermBackwardCompatible);
00051 PARSER_FUNC_PROTO1(ExprBackwardCompatible, int level);
00052 PARSER_FUNC_PROTO1(TermSystemBackwardCompatible, int lev);
00053 PARSER_FUNC_PROTO(ActionArgumentBackwardCompatible);
00054 PARSER_FUNC_PROTO(FuncExpr);
00055 PARSER_FUNC_PROTO(Type);
00056 PARSER_FUNC_PROTO2(_Type, int prec, int lifted);
00057 PARSER_FUNC_PROTO(TypeSet);
00058 PARSER_FUNC_PROTO(FuncType);
00059 PARSER_FUNC_PROTO(_FuncType);
00060 PARSER_FUNC_PROTO(TypingConstraints);
00061 PARSER_FUNC_PROTO(_TypingConstraints);
00062 PARSER_FUNC_PROTO(Metadata);
00063
00064
00065 ParserContext *newParserContext(rError_t *errmsg, Region *r) {
00066 ParserContext *pc = (ParserContext *)malloc(sizeof(ParserContext));
00067 pc->stackTopStackTop = 0;
00068 pc->nodeStackTop = 0;
00069 pc->error = 0;
00070 pc->errloc.exprloc = -1;
00071 pc->region = r;
00072 pc->errmsg = errmsg;
00073 pc->errnode = NULL;
00074 pc->symtable = newHashTable2(100, r);
00075 pc->errmsgbuf[0] = '\0';
00076 pc->tqp = pc->tqtop = pc->tqbot = 0;
00077 return pc;
00078 }
00079
00080 void deleteParserContext(ParserContext *t) {
00081 free(t);
00082 }
00083 int isLocalVariableNode(Node *node) {
00084 return
00085 getNodeType(node)==TK_VAR &&
00086 node->text[0] == '*';
00087 }
00088 int isSessionVariableNode(Node *node) {
00089 return
00090 getNodeType(node)==TK_VAR &&
00091 node->text[0] == '$';
00092 }
00093 int isVariableNode(Node *node) {
00094 return
00095 isLocalVariableNode(node) ||
00096 isSessionVariableNode(node);
00097 }
00098 #define nKeywords 19
00099 char *keywords[nKeywords] = { "in", "let", "match", "with", "for", "forExec", "while", "whileExec", "foreach", "forEachExec", "if", "ifExec", "then", "else", "data", "constructor", "on", "or", "oron"};
00100 int isKeyword(char *text) {
00101 int i;
00102 for(i=0;i<nKeywords;i++) {
00103 if(strcmp(keywords[i], text) == 0) {
00104 return 1;
00105 }
00106 }
00107 return 0;
00108 }
00109
00110 void skipWhitespace(Pointer *expr) {
00111 int ch;
00112 ch = lookAhead(expr, 0);
00113 while (ch!=-1 && (ch==' ' || ch=='\t' || ch=='\r' || ch=='\n')) {
00114 ch = nextChar(expr);
00115 }
00116 }
00117 void skipComments(Pointer *e) {
00118 int ch = lookAhead(e, 0);
00119 while(ch!='\n' && ch!=-1) {
00120 ch = nextChar(e);
00121 }
00122 }
00123 char *findLineCont(char *expr) {
00124 char *e = expr + strlen(expr);
00125 while (e!=expr) {
00126 e--;
00127 if(*e==' ' || *e=='\t' || *e=='\r' || *e=='\n') continue;
00128 if(*e=='\\' || *e==',' || *e==';' || *e=='|' || *e=='#') return e;
00129 break;
00130 }
00131 return NULL;
00132 }
00133
00134
00135
00136
00137
00138 int skip(Pointer *e, char *text, Token **token, ParserContext *pc, int rulegen) {
00139 *token = nextTokenRuleGen(e, pc, rulegen);
00140 if(((*token)->type!=TK_TEXT && (*token)->type!=TK_OP && (*token)->type!=TK_MISC_OP) || strcmp((*token)->text,text)!=0) {
00141 (*token)->type = N_ERROR;
00142 return 0;
00143 }
00144 return 1;
00145 }
00146
00147
00148
00149
00150
00151 Token* nextTokenRuleGen(Pointer* e, ParserContext *context, int rulegen) {
00152 if(context->tqp != context->tqtop) {
00153 Token *token = &(context->tokenQueue[context->tqp]);
00154 INC_MOD(context->tqp, 1024);
00155 return token;
00156 }
00157
00158 Token* token = &(context->tokenQueue[context->tqp]);
00159 INC_MOD(context->tqtop, 1024);
00160 if(context->tqbot == context->tqtop)
00161 INC_MOD(context->tqbot, 1024);
00162 context->tqp = context->tqtop;
00163
00164 while (1) {
00165 skipWhitespace(e);
00166 Label start;
00167 Label pos;
00168 getFPos(&start, e, context);
00169 token->exprloc = start.exprloc;
00170 int ch = lookAhead(e, 0);
00171 if (ch == -1) {
00172 token->type = TK_EOS;
00173 strcpy(token->text, "EOS");
00174 break;
00175 } else {
00176 int i;
00177 if (ch == '{' || ch == '}' || ch == '(' || ch == ')' || ch == ',' || ch == '@' || (ch == '|' && (!rulegen || lookAhead(e, 1) != '|')) || ch == ';' || ch == '?') {
00178 *(token->text) = ch;
00179 (token->text)[1] = '\0';
00180 token->type = TK_MISC_OP;
00181 nextChar(e);
00182 break;
00183 } else if (ch == '#') {
00184 if (!rulegen && lookAhead(e, 1) == '#') {
00185 token->text[0] = ch;
00186 token->text[1] = lookAhead(e, 1);
00187 token->text[2] = '\0';
00188 token->type = TK_MISC_OP;
00189 nextChar(e);
00190 nextChar(e);
00191 break;
00192 } else {
00193 skipComments(e);
00194 continue;
00195 }
00196 } else if(ch == '-' || ch == '=') {
00197 if(lookAhead(e,1)=='>') {
00198 token->text[0] = ch;
00199 token->text[1] = '>';
00200 token->text[2] = '\0';
00201 token->type = TK_MISC_OP;
00202 nextChar(e);
00203 nextChar(e);
00204 break;
00205 }
00206 } else if (ch == ':') {
00207 if (rulegen && lookAhead(e, 1) == ':'
00208 && lookAhead(e, 2) == ':') {
00209 token->text[0] = ch;
00210 token->text[1] = lookAhead(e, 1);
00211 token->text[2] = lookAhead(e, 2);
00212 token->text[3] = '\0';
00213 token->type = TK_MISC_OP;
00214 nextChar(e);
00215 nextChar(e);
00216 } else {
00217 *(token->text) = ch;
00218 (token->text)[1] = '\0';
00219 token->type = TK_MISC_OP;
00220 }
00221 nextChar(e);
00222 break;
00223 } else if (ch == '*' || ch == '$') {
00224 token->type = ch == '*' ? TK_LOCAL_VAR : TK_SESSION_VAR;
00225
00226 ch = nextChar(e);
00227 if (ch == '_' || isalpha(ch)) {
00228 ch = nextChar(e);
00229 while (ch == '_' || isalnum(ch)) {
00230 ch = nextChar(e);
00231 }
00232 FPOS;
00233 dupString(e, &start, (int) (pos.exprloc - start.exprloc), token->text);
00234 break;
00235 } else {
00236 seekInFile(e, start.exprloc);
00237 }
00238 }
00239 char op[100];
00240 dupString(e, &start, 10, op);
00241 int found = 0;
00242 for (i = 0; i < num_ops; i++) {
00243 int len = strlen(new_ops[i].string);
00244 if (strncmp(op, new_ops[i].string, len) == 0 &&
00245 (!isalpha(new_ops[i].string[0])
00246 || !isalnum(op[len]))) {
00247 strcpy(token->text, new_ops[i].string);
00248 token->type = TK_OP;
00249 nextChars(e, len);
00250 found = 1;
00251 break;
00252 }
00253 }
00254 if (found)
00255 break;
00256 if (isdigit(ch) || ch == '.') {
00257 ch = nextChar(e);
00258 while (isdigit(ch) || ch == '.') {
00259 ch = nextChar(e);
00260 }
00261 FPOS;
00262 dupString(e, &start, (int) (pos.exprloc - start.exprloc), token->text);
00263 if (strchr(token->text, '.')) {
00264 token->type = TK_DOUBLE;
00265 } else {
00266 token->type = TK_INT;
00267 }
00268 } else if (ch == '_' || isalpha(ch) || ch == '~') {
00269 ch = nextChar(e);
00270 while (ch == '_' || isalnum(ch)) {
00271 ch = nextChar(e);
00272 }
00273 FPOS;
00274 dupString(e, &start, (int) (pos.exprloc - start.exprloc), token->text);
00275 token->type = TK_TEXT;
00276 } else if (ch == '\"') {
00277 nextString(e, token->text, token->vars);
00278 token->type = TK_STRING;
00279 } else if (ch == '\'') {
00280 nextString2(e, token->text, token->vars);
00281 token->type = TK_STRING;
00282 } else if (ch == '`') {
00283 if(lookAhead(e, 1) == '`') {
00284 if(nextStringBase2(e, token->text, "``")==-1) {
00285 token->type = N_ERROR;
00286 } else {
00287 token->type = TK_STRING;
00288 token->vars[0] = -1;
00289 }
00290 } else {
00291 nextStringBase(e, token->text, "`", 1, '\\', token->vars);
00292 token->type = TK_BACKQUOTED;
00293 }
00294 } else {
00295 token->type = N_ERROR;
00296 }
00297 break;
00298 }
00299 }
00300 return token;
00301 }
00302
00303 void pushback(Pointer *e, Token *token, ParserContext *context) {
00304 if(token->type == TK_EOS) {
00305 return;
00306 }
00307 DEC_MOD(context->tqp, 1024);
00308 }
00309
00310 void syncTokenQueue(Pointer *e, ParserContext *context) {
00311 if(context->tqp == context->tqtop) {
00312 return;
00313 }
00314 Token *nextToken = &context->tokenQueue[context->tqp];
00315 seekInFile(e, nextToken->exprloc);
00316 context->tqtop = context->tqp;
00317 }
00318
00319 int eol(char ch) {
00320 return ch=='\n' || ch=='\r';
00321 }
00322
00323
00324
00325
00326
00327
00328 PARSER_FUNC_BEGIN1(Rule, int backwardCompatible)
00329 char *rk;
00330 int rulegen = 0;
00331 TRY(defType)
00332 TTEXT("data");
00333 NT(RuleName);
00334 BUILD_NODE(N_DATA_DEF, "DATA", &start, 1, 1);
00335 int n = 0;
00336 OPTIONAL_BEGIN(consDefs)
00337 TTEXT("=");
00338 OPTIONAL_BEGIN(semicolon)
00339 TTEXT("|");
00340 OPTIONAL_END(semicolon)
00341 LOOP_BEGIN(cons)
00342 Label cpos = *FPOS;
00343 TTYPE(TK_TEXT);
00344 BUILD_NODE(TK_TEXT, token->text, &pos, 0, 0);
00345 TTEXT(":");
00346 NT(FuncType);
00347 BUILD_NODE(N_CONSTRUCTOR_DEF, "CONSTR", &cpos, 2, 2);
00348 n++;
00349 TRY(delim)
00350 TTEXT("|");
00351 OR(delim)
00352 DONE(cons);
00353 END_TRY(delim)
00354 LOOP_END(cons)
00355 OPTIONAL_END(consDefs)
00356 OPTIONAL_BEGIN(semicolon)
00357 TTEXT(";");
00358 OPTIONAL_END(semicolon)
00359 n = n+1;
00360 BUILD_NODE(N_RULE_PACK, "INDUCT", &start, n, n);
00361 OR(defType)
00362 TTEXT("constructor");
00363 TTYPE(TK_TEXT);
00364 BUILD_NODE(TK_TEXT, token->text, &pos, 0, 0);
00365 TTEXT(":")
00366 NT(FuncType);
00367 BUILD_NODE(N_CONSTRUCTOR_DEF, "CONSTR", &start, 2, 2);
00368 BUILD_NODE(N_RULE_PACK, "CONSTR", &start, 1, 1);
00369 OR(defType)
00370 TTYPE(TK_TEXT);
00371 BUILD_NODE(TK_TEXT, token->text, &pos, 0, 0);
00372 TTEXT(":");
00373 NT(FuncType);
00374 BUILD_NODE(N_EXTERN_DEF, "EXTERN", &start, 2, 2);
00375 BUILD_NODE(N_RULE_PACK, "EXTERN", &start, 1, 1);
00376 OR(defType)
00377 NT(RuleName);
00378 TRY(ruleType)
00379 TTEXT("{");
00380 rulegen = 1;
00381 rk = "REL";
00382 OR(ruleType)
00383 TTEXT("|");
00384 rulegen = 0;
00385 rk = "REL";
00386 OR(ruleType)
00387 TTEXT("=");
00388 rulegen = 1;
00389 rk = "FUNC";
00390 END_TRY(ruleType);
00391 if(strcmp(rk, "FUNC")==0) {
00392 BUILD_NODE(TK_BOOL, "true", FPOS, 0, 0);
00393 NT(FuncExpr);
00394 NT(Metadata);
00395 OPTIONAL_BEGIN(semicolon)
00396 TTEXT(";");
00397 OPTIONAL_END(semicolon)
00398 BUILD_NODE(N_RULE,"RULE", &start,5, 5);
00399 BUILD_NODE(N_RULE_PACK,rk, &start,1, 1);
00400 /* } else if(PARSER_LAZY) {
00401 char buf[MAX_RULE_LEN];
00402 Label rcpos = *FPOS;
00403 getRuleCode(buf, e, rulegen, context);
00404 BUILD_NODE(N_RULE_CODE, buf, &rcpos, 0, 0);
00405 BUILD_NODE(N_UNPARSED,"UNPARSED", &start,2, 2);
00406 BUILD_NODE(N_RULE_PACK,rk, &start,1, 1); */
00407 } else if(rulegen) {
00408 int numberOfRules = 0;
00409 LOOP_BEGIN(rule)
00410 TRY(rulePack)
00411 TRY(rulePackCond)
00412 TTEXT("ON");
00413 OR(rulePackCond)
00414 TTEXT("on");
00415 OR(rulePackCond)
00416 TTEXT("ORON");
00417 OR(rulePackCond)
00418 TTEXT("oron");
00419 END_TRY(rulePackCond)
00420 NT2(Term, 1, MIN_PREC);
00421 TTEXT("{");
00422 NT2(Actions, 1, 0);
00423 TTEXT("}");
00424 NT(Metadata);
00425 BUILD_NODE(N_RULE, "RULE", &start, 5, 4);
00426 SWAP;
00427 numberOfRules++;
00428 OR(rulePack)
00429 TRY(rulePackUncond)
00430 TTEXT("OR");
00431 OR(rulePackUncond)
00432 TTEXT("or");
00433 END_TRY(rulePackUncond)
00434 BUILD_NODE(TK_BOOL, "true", FPOS, 0, 0);
00435 TTEXT("{");
00436 NT2(Actions, 1, 0);
00437 TTEXT("}");
00438 NT(Metadata);
00439 BUILD_NODE(N_RULE, "RULE", &start, 5, 4);
00440 SWAP;
00441 numberOfRules++;
00442 OR(rulePack)
00443 ABORT(numberOfRules == 0);
00444 TTEXT("}");
00445 DONE(rule);
00446 OR(rulePack)
00447 ABORT(numberOfRules != 0);
00448 BUILD_NODE(TK_BOOL, "true", FPOS, 0, 0);
00449 NT2(Actions, 1, 0);
00450 TTEXT("}");
00451 NT(Metadata);
00452 numberOfRules = 1;
00453 BUILD_NODE(N_RULE, "RULE", &start, 5, 4);
00454 SWAP;
00455 DONE(rule);
00456 END_TRY(rulePack)
00457 LOOP_END(rule)
00458 (void) POP;
00459 BUILD_NODE(N_RULE_PACK, rk, &start, numberOfRules, numberOfRules);
00460 } else {
00461 Label pos = *FPOS;
00462 TRY(ruleCond)
00463 /* empty condition */
00464 TTEXT("|");
00465 BUILD_NODE(TK_BOOL, "true", FPOS, 0, 0);
00466 OR(ruleCond)
00467 if(backwardCompatible >= 0) {
00468 NT1(ExprBackwardCompatible, 0);
00469 } else {
00470 NT2(Term, 0, MIN_PREC);
00471 }
00472 TTEXT("|");
00473 BUILD_NODE(N_TUPLE, TUPLE, &pos, 1, 1);
00474 END_TRY(ruleCond)
00475
00476
00477 NT2(Actions, 0, backwardCompatible >= 0? 1: 0);
00478 TTEXT("|");
00479 NT2(Actions, 0, backwardCompatible>= 0? 1: 0);
00480 int n = 0;
00481 Label metadataStart = *FPOS;
00482 OPTIONAL_BEGIN(ruleId)
00483 TTEXT("|");
00484 TTYPE(TK_INT);
00485 BUILD_NODE(TK_STRING,"id", &pos, 0, 0);
00486 BUILD_NODE(TK_STRING,token->text, &pos, 0, 0);
00487 BUILD_NODE(TK_STRING,"", &pos, 0, 0);
00488 BUILD_NODE(N_AVU,AVU, &pos, 3, 3);
00489 n++;
00490 OPTIONAL_END(ruleId)
00491 BUILD_NODE(N_META_DATA, META_DATA, &metadataStart, n, n);
00492 BUILD_NODE(N_RULE,"RULE", &start, 5, 5);
00493 BUILD_NODE(N_RULE_PACK, rk, &start, 1, 1);
00494 }
00495 /*OR(defType)
00496 TTYPE(TK_LOCAL_VAR);
00497 BUILD_NODE(TK_VAR, token->text, &pos, 0, 0);
00498 TTEXT("=");
00499 NT2(Term, 0, MIN_PREC);
00500 BUILD_NODE(N_RULE_PACK, "GLOBAL", &start, 2, 2);*/
00501 END_TRY(defType)
00502 PARSER_FUNC_END(Rule)
00503
00504 PARSER_FUNC_BEGIN(RuleName)
00505 int rulegen = 0;
00506 TTYPE(TK_TEXT);
00507 char *ruleName = cpStringExt(token->text, context->region);
00508 Label paramListStart = *FPOS;
00509 TRY(params)
00510 TTEXT("(");
00511 int n = 0;
00512 LOOP_BEGIN(params)
00513 NT2(Term, rulegen, MIN_PREC);
00514 n++;
00515 CHOICE_BEGIN(paramType)
00516 BRANCH_BEGIN(paramType)
00517 TTEXT(":");
00518 NT(Type);
00519 BRANCH_END(paramType)
00520 BRANCH_BEGIN(paramType)
00521 BUILD_NODE(T_UNSPECED, NULL, FPOS, 0, 0);
00522 BRANCH_END(paramType)
00523 CHOICE_END(paramType)
00524 CHOICE_BEGIN(paramDelim)
00525 BRANCH_BEGIN(paramDelim)
00526 TTEXT(",");
00527 BRANCH_END(paramDelim)
00528 BRANCH_BEGIN(paramDelim)
00529 TTEXT(")");
00530 DONE(params);
00531 BRANCH_END(paramDelim)
00532 CHOICE_END(paramDelim)
00533 LOOP_END(params);
00534 UNZIP(n);
00535 BUILD_NODE(N_PARAM_TYPE_LIST, "paramTypelist", ¶mListStart, n, n);
00536 Node *node = POP;
00537 BUILD_NODE(N_PARAM_LIST, "paramlist", ¶mListStart, n, n);
00538 PUSH(node);
00539 OR(params)
00540 OPTIONAL_BEGIN(epl)
00541 TTEXT("(");
00542 TTEXT(")");
00543 OPTIONAL_END(epl)
00544 BUILD_NODE(N_PARAM_LIST, "paramlist", ¶mListStart, 0, 0);
00545 BUILD_NODE(N_PARAM_TYPE_LIST, "paramTypelist", ¶mListStart, 0, 0);
00546 END_TRY(params)
00547
00548 TRY(retType)
00549 TTEXT(":");
00550 NT(FuncType);
00551 OR(retType)
00552 BUILD_NODE(T_UNSPECED, NULL, FPOS, 0, 0);
00553 END_TRY(retType)
00554 BUILD_NODE(N_RULE_NAME, ruleName, &start, 3, 3);
00555 PARSER_FUNC_END(RuleName)
00556
00557 PARSER_FUNC_BEGIN(Metadata)
00558 int rulegen = 1;
00559 int n = 0;
00560 LOOP_BEGIN(metadata)
00561 TRY(avu)
00562 TTEXT("@");
00563 TTEXT("(");
00564 TTYPE(TK_STRING);
00565 BUILD_NODE(TK_STRING, token->text, &pos, 0, 0);
00566 TTEXT(",");
00567 TTYPE(TK_STRING);
00568 BUILD_NODE(TK_STRING, token->text, &pos, 0, 0);
00569 TRY(u)
00570 TTEXT(",");
00571 TTYPE(TK_STRING);
00572 BUILD_NODE(TK_STRING, token->text, &pos, 0, 0);
00573 TTEXT(")");
00574 OR(u)
00575 TTEXT(")");
00576 BUILD_NODE(TK_STRING, "", &pos, 0, 0);
00577 END_TRY(u)
00578 BUILD_NODE(N_AVU, AVU, &pos, 3, 3);
00579 n++;
00580 OR(avu)
00581 DONE(metadata);
00582 END_TRY(avu)
00583 LOOP_END(metadata)
00584 BUILD_NODE(N_META_DATA, META_DATA, &start, n, n);
00585 PARSER_FUNC_END(Metadata)
00586
00587
00588 PARSER_FUNC_BEGIN(FuncExpr)
00589 int rulegen = 1;
00590 NT2(Term, 1, MIN_PREC);
00591 CHOICE_BEGIN(reco)
00592 BRANCH_BEGIN(reco)
00593 TTEXT(":::");
00594 NT2(Term, 1, MIN_PREC);
00595 BRANCH_END(reco)
00596 BRANCH_BEGIN(reco)
00597 BUILD_APP_NODE("nop", FPOS, 0);
00598 BRANCH_END(reco)
00599 CHOICE_END(reco)
00600 PARSER_FUNC_END(FuncExpr)
00601
00602 PARSER_FUNC_BEGIN2(Actions, int rulegen, int backwardCompatible)
00603 int n = 0;
00604 TRY(actions)
00605 ABORT(backwardCompatible);
00606 TTEXT_LOOKAHEAD("}");
00607 OR(actions)
00608 LOOP_BEGIN(actions);
00609 if(!backwardCompatible) {
00610 NT2(Term, rulegen, MIN_PREC);
00611 } else {
00612 NT(TermBackwardCompatible);
00613 }
00614 if(rulegen) {
00615 CHOICE_BEGIN(reco)
00616 BRANCH_BEGIN(reco)
00617 TTEXT(":::");
00618 NT2(Term, rulegen, MIN_PREC);
00619 BRANCH_END(reco)
00620 BRANCH_BEGIN(reco)
00621 BUILD_APP_NODE("nop", NULL, 0);
00622 BRANCH_END(reco)
00623 CHOICE_END(reco)
00624 }
00625 n++;
00626 if(rulegen) {
00627 OPTIONAL_BEGIN(actionSemiColon)
00628 TTEXT(";");
00629 OPTIONAL_END(actionSemiColon)
00630 OPTIONAL_BEGIN(actionSemiColonBrace)
00631 TTEXT_LOOKAHEAD("}");
00632 DONE(actions);
00633 OPTIONAL_END(actionSemiColonBrace)
00634 } else {
00635 CHOICE_BEGIN(actionDelim)
00636 BRANCH_BEGIN(actionDelim)
00637 TTEXT("##");
00638 BRANCH_END(actionDelim)
00639 BRANCH_BEGIN(actionDelim)
00640 DONE(actions);
00641 BRANCH_END(actionDelim)
00642 CHOICE_END(actionDelim)
00643 }
00644 LOOP_END(actions)
00645 END_TRY(actions)
00646 if(rulegen)
00647 UNZIP(n);
00648 BUILD_NODE(N_ACTIONS, "ACTIONS", &start, n, n);
00649 if(rulegen) {
00650 Node *node = POP;
00651 BUILD_NODE(N_ACTIONS, "ACTIONS", &start, n, n);
00652 PUSH(node);
00653 }
00654 PARSER_FUNC_END(Actions)
00655
00656 PARSER_FUNC_BEGIN(ActionsToStrings)
00657 int rulegen = 1;
00658 int n = 0;
00659 #define bufferSize 10000
00660 char actiBuffer[bufferSize], recoBuffer[bufferSize];
00661 int actiP = 0, recoP = 0;
00662 Label start, finish;
00663 TRY(actions)
00664 TTEXT_LOOKAHEAD("}");
00665 OR(actions)
00666 LOOP_BEGIN(actions);
00667 start = *FPOS;
00668 NT2(Term, rulegen, MIN_PREC);
00669 (void) POP;
00670 finish = *FPOS;
00671 ABORT(actiP + finish.exprloc - start.exprloc + 1 >= bufferSize);
00672 dupString(e, &start, finish.exprloc - start.exprloc, actiBuffer + actiP);
00673 actiP += finish.exprloc - start.exprloc;
00674 actiBuffer[actiP++] = ';';
00675 if(rulegen) {
00676 CHOICE_BEGIN(reco)
00677 BRANCH_BEGIN(reco)
00678 TTEXT(":::");
00679 start = *FPOS;
00680 NT2(Term, rulegen, MIN_PREC);
00681 (void) POP;
00682 finish = *FPOS;
00683 ABORT(finish.exprloc - start.exprloc + 1 + recoP >= bufferSize);
00684 dupString(e, &start, finish.exprloc - start.exprloc, recoBuffer + recoP);
00685 recoP += finish.exprloc - start.exprloc;
00686 recoBuffer[actiP++] = ';';
00687 BRANCH_END(reco)
00688 BRANCH_BEGIN(reco)
00689 ABORT(recoP + 4 >= bufferSize);
00690 strcpy(recoBuffer + recoP, "nop;");
00691 recoP += 4;
00692 BRANCH_END(reco)
00693 CHOICE_END(reco)
00694 }
00695 n++;
00696 if(rulegen) {
00697 OPTIONAL_BEGIN(actionSemiColon)
00698 TTEXT(";");
00699 OPTIONAL_END(actionSemiColon)
00700 OPTIONAL_BEGIN(actionSemiColonBrace)
00701 TTEXT_LOOKAHEAD("}");
00702 DONE(actions);
00703 OPTIONAL_END(actionSemiColonBrace)
00704 } else {
00705 CHOICE_BEGIN(actionDelim)
00706 BRANCH_BEGIN(actionDelim)
00707 TTEXT("##");
00708 BRANCH_END(actionDelim)
00709 BRANCH_BEGIN(actionDelim)
00710 DONE(actions);
00711 BRANCH_END(actionDelim)
00712 CHOICE_END(actionDelim)
00713 }
00714 LOOP_END(actions)
00715 END_TRY(actions)
00716 actiBuffer[actiP] = recoBuffer[recoP] = '\0';
00717 BUILD_NODE(TK_STRING, actiBuffer, &start, 0, 0);
00718 BUILD_NODE(TK_STRING, recoBuffer, &start, 0, 0);
00719 PARSER_FUNC_END(ActionsToStrings)
00720
00721 PARSER_FUNC_BEGIN1(TermSystemBackwardCompatible, int level)
00722 int rulegen = 0;
00723 TRY(func)
00724 TTEXT("ifExec");
00725 TTEXT("(");
00726 if(level == 1) {
00727 NT1(ExprBackwardCompatible, 0);
00728 } else {
00729 NT2(Term, 0, MIN_PREC);
00730 }
00731 TTEXT(",");
00732 NT2(Actions, 0, level);
00733 TTEXT(",");
00734 NT2(Actions, 0, level);
00735 TTEXT(",");
00736 NT2(Actions, 0, level);
00737 TTEXT(",");
00738 NT2(Actions, 0, level);
00739 TTEXT(")");
00740 BUILD_APP_NODE("if", &start, 5);
00741 OR(func)
00742 TTEXT("whileExec");
00743 TTEXT("(");
00744 if(level == 1) {
00745 NT1(ExprBackwardCompatible, 0);
00746 } else {
00747 NT2(Term, 0, MIN_PREC);
00748 }
00749 TTEXT(",");
00750 NT2(Actions, 0, level);
00751 TTEXT(",");
00752 NT2(Actions, 0, level);
00753 TTEXT(")");
00754 BUILD_APP_NODE("while", &start, 3);
00755 OR(func)
00756 TTEXT("forEachExec");
00757 TTEXT("(");
00758 TTYPE(TK_LOCAL_VAR);
00759 BUILD_NODE(TK_VAR, token->text, &start, 0, 0);
00760 TTEXT(",");
00761 NT2(Actions, 0, level);
00762 TTEXT(",");
00763 NT2(Actions, 0, level);
00764 TTEXT(")");
00765 BUILD_APP_NODE("foreach", &start, 3);
00766
00767 OR(func)
00768 TTEXT("assign");
00769 TTEXT("(");
00770 TTYPE(TK_LOCAL_VAR);
00771 BUILD_NODE(TK_VAR, token->text, &pos, 0, 0);
00772 TTEXT(",");
00773 if(level == 1) {
00774 TRY(expr)
00775 NT1(ExprBackwardCompatible, 1);
00776 OR(expr)
00777 NT(ActionArgumentBackwardCompatible);
00778 END_TRY(expr)
00779 } else {
00780 NT2(Term, 0, MIN_PREC);
00781 }
00782 TTEXT(")");
00783 if(level == 1) {
00784 BUILD_APP_NODE("assignStr", &start, 2);
00785 } else {
00786 BUILD_APP_NODE("assign", &start, 2);
00787 }
00788 OR(func)
00789 TTEXT("forExec");
00790 TTEXT("(");
00791 NT2(Term, 0, MIN_PREC);
00792 TTEXT(",");
00793 NT2(Term, 0, MIN_PREC);
00794 TTEXT(",");
00795 NT2(Term, 0, MIN_PREC);
00796 TTEXT(",");
00797 NT2(Actions, 0, level);
00798 TTEXT(",");
00799 NT2(Actions, 0, level);
00800 TTEXT(")");
00801 BUILD_APP_NODE("for", &start, 5);
00802 OR(func)
00803 TTEXT("breakExec");
00804 BUILD_APP_NODE("break", &start, 0);
00805 OR(func)
00806 TTEXT("delayExec");
00807 TTEXT("(");
00808 NT(ActionArgumentBackwardCompatible)
00809 TTEXT(",");
00810 Token strtoken;
00811 nextActionArgumentStringBackwardCompatible(e, &strtoken);
00812 if(strtoken.type != TK_STRING) {
00813 BUILD_NODE(N_ERROR, "reached the end of stream while parsing an action argument", FPOS,0,0);
00814 } else {
00815 BUILD_NODE(TK_STRING, strtoken.text, &pos, 0, 0);
00816 }
00817 TTEXT(",");
00818 nextActionArgumentStringBackwardCompatible(e, &strtoken);
00819 if(strtoken.type != TK_STRING) {
00820 BUILD_NODE(N_ERROR, "reached the end of stream while parsing an action argument", FPOS,0,0);
00821 } else {
00822 BUILD_NODE(TK_STRING, strtoken.text, &pos, 0, 0);
00823 }
00824 TTEXT(")");
00825 BUILD_APP_NODE("delayExec", &start, 3);
00826 OR(func)
00827 TTEXT("remoteExec");
00828 TTEXT("(");
00829
00830 NT(ActionArgumentBackwardCompatible)TTEXT(",");
00831 NT(ActionArgumentBackwardCompatible)TTEXT(",");
00832 Token strtoken;
00833 nextActionArgumentStringBackwardCompatible(e, &strtoken);
00834 if(strtoken.type != TK_STRING) {
00835 BUILD_NODE(N_ERROR, "reached the end of stream while parsing an action argument", FPOS,0,0);
00836 } else {
00837 BUILD_NODE(TK_STRING, strtoken.text, &pos, 0, 0);
00838 }TTEXT(",");
00839 nextActionArgumentStringBackwardCompatible(e, &strtoken);
00840 if(strtoken.type != TK_STRING) {
00841 BUILD_NODE(N_ERROR, "reached the end of stream while parsing an action argument", FPOS,0,0);
00842 } else {
00843 BUILD_NODE(TK_STRING, strtoken.text, &pos, 0, 0);
00844 }
00845 TTEXT(")");
00846 BUILD_APP_NODE("remoteExec", &start, 4);
00847 END_TRY(func)
00848 PARSER_FUNC_END(TermSystemBackwardCompatible)
00849
00850 PARSER_FUNC_BEGIN1(ExprBackwardCompatible, int level)
00851 int rulegen =0;
00852 TRY(func)
00853 ABORT(level == 1);
00854 NT(TermBackwardCompatible);
00855 OR(func)
00856 TTEXT("(");
00857 NT1(ExprBackwardCompatible, level);
00858 TTEXT(")");
00859 OR(func)
00860 NT1(T, 0);
00861 END_TRY(func)
00862 OPTIONAL_BEGIN(term2)
00863 TTYPE(TK_OP);
00864 char *fn = cpStringExt(token->text, context->region);
00865 ABORT(!isBinaryOp(token));
00866 if(TOKEN_TEXT("like") || TOKEN_TEXT("not like") || TOKEN_TEXT("==") || TOKEN_TEXT("!=")) {
00867 BUILD_APP_NODE("str", FPOS, 1);
00868 NT(ActionArgumentBackwardCompatible);
00869 } else if(TOKEN_TEXT("+") || TOKEN_TEXT("-") || TOKEN_TEXT("*") || TOKEN_TEXT("/") || TOKEN_TEXT("<") || TOKEN_TEXT("<=") || TOKEN_TEXT(">") || TOKEN_TEXT(">=")) {
00870 BUILD_APP_NODE("double", FPOS, 1);
00871 NT1(ExprBackwardCompatible, 1);
00872 BUILD_APP_NODE("double", FPOS, 1);
00873 } else if(TOKEN_TEXT("%%") || TOKEN_TEXT("&&")) {
00874 BUILD_APP_NODE("bool", FPOS, 1);
00875 NT1(ExprBackwardCompatible, 1);
00876 BUILD_APP_NODE("bool", FPOS, 1);
00877 } else {
00878 BUILD_APP_NODE("str", FPOS, 1);
00879 NT1(ExprBackwardCompatible, 1);
00880 BUILD_APP_NODE("str", FPOS, 1);
00881 }
00882 BUILD_APP_NODE(fn, &start, 2);
00883 OPTIONAL_END(term2)
00884 PARSER_FUNC_END(ExprBackwardCompatible)
00885
00886 PARSER_FUNC_BEGIN(TermBackwardCompatible)
00887 int rulegen =0;
00888 TRY(func)
00889 NT1(TermSystemBackwardCompatible, 1);
00890
00891 OR(func)
00892 TTYPE(TK_TEXT);
00893 char *fn = cpStringExt(token->text, context->region);
00894 TTEXT("(");
00895 TTEXT(")");
00896 BUILD_APP_NODE(fn, &start, 0);
00897
00898 OR(func)
00899 TTYPE(TK_TEXT);
00900 char *fn = cpStringExt(token->text, context->region);
00901 TTEXT("(");
00902 int n = 0;
00903 LOOP_BEGIN(func)
00904 NT(ActionArgumentBackwardCompatible);
00905 n++;
00906 CHOICE_BEGIN(paramDelim)
00907 BRANCH_BEGIN(paramDelim)
00908 TTEXT(",");
00909 BRANCH_END(paramDelim)
00910 BRANCH_BEGIN(paramDelim)
00911 TTEXT(")");
00912 DONE(func);
00913 BRANCH_END(paramDelim)
00914 CHOICE_END(paramDelim)
00915 LOOP_END(func)
00916 BUILD_APP_NODE(fn, &start, n);
00917 OR(func)
00918 TTYPE(TK_TEXT);
00919 char *fn = cpStringExt(token->text, context->region);
00920 BUILD_APP_NODE(fn, &start, 0);
00921
00922 END_TRY(func)
00923
00924 PARSER_FUNC_END(ValueBackwardCompatible)
00925
00926
00927 PARSER_FUNC_BEGIN(ActionArgumentBackwardCompatible)
00928 int rulegen = 0;
00929 Token strtoken;
00930 TRY(var)
00931 Label vpos = *FPOS;
00932 TTYPE(TK_LOCAL_VAR);
00933 char *vn = cpStringExt(token->text, context->region);
00934 TTEXT3(",", "|", ")");
00935 PUSHBACK;
00936 BUILD_NODE(TK_VAR, vn, &vpos, 0, 0);
00937 OR(var)
00938 syncTokenQueue(e, context);
00939
00940 nextActionArgumentStringBackwardCompatible(e, &strtoken);
00941 if(strtoken.type != TK_STRING) {
00942 BUILD_NODE(N_ERROR, "reached the end of stream while parsing an action argument", FPOS,0,0);
00943 } else {
00944 NT1(StringExpression, &strtoken);
00945 }
00946 END_TRY(var)
00947 PARSER_FUNC_END(ActionArgumentBackwardCompatible)
00948
00949 PARSER_FUNC_BEGIN2(Term, int rulegen, int prec)
00950 NT1(Value, rulegen);
00951 int done = 0;
00952 while (!done && NO_SYNTAX_ERROR) {
00953 CHOICE_BEGIN(term)
00954 BRANCH_BEGIN(term)
00955 TTYPE(TK_OP);
00956 ABORT(!isBinaryOp(token));
00957 if(prec>=getBinaryPrecedence(token)) {
00958 PUSHBACK;
00959 done = 1;
00960 } else {
00961 char *fn;
00962 if(TOKEN_TEXT("=")) {
00963 fn = "assign";
00964 } else {
00965 fn = token->text;
00966 }
00967 NT2(Term, rulegen, getBinaryPrecedence(token));
00968 #ifdef DEBUG_VERBOSE
00969 char err[1024];
00970 generateErrMsg(fn, FPOS->exprloc, "ftest", err);
00971 printf("%s", err);
00972 #endif
00973 BUILD_APP_NODE(fn, &start, 2);
00974 }
00975
00976 BRANCH_END(term)
00977 BRANCH_BEGIN(term)
00978 TRY(syntacticalArg)
00979 TTEXT_LOOKAHEAD("(");
00980 OR(syntacticalArg)
00981 TTEXT_LOOKAHEAD("[");
00982 END_TRY(syntacticalArg)
00983
00984 Token appToken;
00985 strcpy(appToken.text, "@@");
00986 NT2(Term, rulegen, getBinaryPrecedence(&appToken));
00987 BUILD_NODE(N_APPLICATION, APPLICATION, &start, 2, 2);
00988 BRANCH_END(term)
00989 BRANCH_BEGIN(term)
00990 done = 1;
00991 BRANCH_END(term)
00992 CHOICE_END(term)
00993 }
00994 if(!done) {
00995 break;
00996 }
00997 PARSER_FUNC_END(Term)
00998
00999 PARSER_FUNC_BEGIN1(StringExpression, Token *tk)
01000 int rulegen = 0;
01001 Token *strToken = NULL;
01002 if(tk == NULL) {
01003 TTYPE(TK_STRING);
01004 strToken = token;
01005 } else {
01006 strToken = tk;
01007 }
01008 int i = 0, k = 0;
01009 pos.base = e->base;
01010 long startLoc = strToken->exprloc;
01011 char *str = strToken->text;
01012 int st[100];
01013 int end[100];
01014 int noi = 1;
01015 st[0] = 0;
01016 end[0] = strlen(str);
01017 while(strToken->vars[i]!=-1) {
01018 /* this string contains reference to vars */
01019 int vs = strToken->vars[i];
01020 i++;
01021 if(!isalpha(str[vs+1]) && str[vs+1]!='_') {
01022 continue;
01023 }
01024 int ve;
01025 ve = vs+2;
01026 while(isalnum(str[ve]) || str[ve]=='_') ve++;
01027 end[noi]=end[noi-1];
01028 end[noi-1]=vs;
01029 st[noi]=ve;
01030 noi++;
01031 }
01032 char sbuf[MAX_RULE_LEN];
01033 char delim[1];
01034 delim[0] = '\0';
01035 strncpy(sbuf, str+st[0], end[0]-st[0]);
01036 strcpy(sbuf+end[0]-st[0], delim);
01037 pos.exprloc = startLoc + st[0];
01038 int startloc = pos.exprloc;
01039 BUILD_NODE(TK_STRING, sbuf, &pos,0,0);
01040 k=1; // JMC cppcheck - syntax error
01041 while(k<noi) { // JMC cppcheck - syntax error
01042 //for(k=1;k<noi;k++) {
01043 strncpy(sbuf, str+end[k-1], st[k]-end[k-1]); /* var */
01044 strcpy(sbuf+st[k]-end[k-1], delim);
01045 pos.exprloc = startLoc + end[k-1];
01046 BUILD_NODE(TK_VAR, sbuf, &pos, 0, 0);
01047
01048 BUILD_APP_NODE("str", &pos, 1);
01049
01050 pos.exprloc = startloc;
01051 BUILD_APP_NODE("++", &pos, 2);
01052
01053 strncpy(sbuf, str+st[k], end[k]-st[k]);
01054 strcpy(sbuf+end[k]-st[k], delim);
01055 pos.exprloc = startLoc + st[k];
01056 BUILD_NODE(TK_STRING, sbuf, &pos, 0, 0);
01057
01058 pos.exprloc = startloc;
01059 BUILD_APP_NODE("++", &pos, 2);
01060 k++; // JMC cppcheck - syntax error
01061 }
01062 PARSER_FUNC_END(StringExpression)
01063
01064 PARSER_FUNC_BEGIN1(T, int rulegen)
01065 TRY(value)
01066 TTYPE(TK_LOCAL_VAR);
01067 BUILD_NODE(TK_VAR, token->text, &pos,0,0);
01068 OR(value)
01069 TTYPE(TK_SESSION_VAR);
01070 BUILD_NODE(TK_VAR, token->text, &pos,0,0);
01071 OR(value)
01072 TTYPE(TK_INT);
01073 BUILD_NODE(TK_INT, token->text, &start, 0, 0);
01074 OR(value)
01075 TTYPE(TK_DOUBLE);
01076 BUILD_NODE(TK_DOUBLE, token->text, &start, 0, 0);
01077 END_TRY(value)
01078 PARSER_FUNC_END(StringExpression)
01079
01080 PARSER_FUNC_BEGIN1(Value, int rulegen)
01081 TRY(value)
01082 NT1(T, rulegen);
01083 OR(value)
01084 TTEXT2("true", "false");
01085 BUILD_NODE(TK_BOOL, token->text, &pos,0,0);
01086 OR(value)
01087 TTEXT("(");
01088 TRY(tuple)
01089 TTEXT(")");
01090 BUILD_NODE(N_TUPLE, TUPLE, &start, 0, 0);
01091 OR(tuple)
01092 NT2(Term, rulegen, MIN_PREC);
01093 int n = 1;
01094 LOOP_BEGIN(tupleLoop)
01095 TRY(tupleComp)
01096 TTEXT(",");
01097 NT2(Term, rulegen, MIN_PREC);
01098 n++;
01099 OR(tupleComp)
01100 TTEXT(")");
01101 DONE(tupleLoop);
01102 END_TRY(tupleComp)
01103 LOOP_END(tupleLoop)
01104 BUILD_NODE(N_TUPLE, TUPLE, &start, n, n);
01105
01106
01107 END_TRY(tuple)
01108
01109 OR(value)
01110 TTEXT("{");
01111 NT2(Actions, rulegen, 0);
01112 if(rulegen)
01113 BUILD_NODE(N_ACTIONS_RECOVERY, "ACTIONS_RECOVERY", &start, 2,2);
01114 TTEXT("}");
01115
01116 OR(value)
01117 TTYPE(TK_OP);
01118 ABORT(!isUnaryOp(token));
01119 NT2(Term, rulegen, getUnaryPrecedence(token));
01120 char *fn;
01121 if(strcmp(token->text, "-")==0) {
01122 fn = "neg";
01123 } else {
01124 fn = token->text;
01125 }
01126 BUILD_APP_NODE(fn, &start,1);
01127
01128 OR(value)
01129 TRY(func)
01130 ABORT(!rulegen);
01131 TRY(funcIf)
01132 TTEXT("if");
01133 TTEXT("(");
01134 NT2(Term, 1, MIN_PREC);
01135 TTEXT(")");
01136 OPTIONAL_BEGIN(ifThen)
01137 TTEXT("then");
01138 OPTIONAL_END(ifThen)
01139 TTEXT("{");
01140 NT2(Actions, 1, 0);
01141 TTEXT("}");
01142 TRY(ifElse)
01143 TTEXT("else");
01144 TTEXT_LOOKAHEAD("if");
01145 NT2(Term, 1, MIN_PREC);
01146 BUILD_NODE(N_ACTIONS, "ACTIONS", &pos, 1, 1);
01147 BUILD_APP_NODE("nop", FPOS, 0);
01148 BUILD_NODE(N_ACTIONS, "ACTIONS", FPOS, 1, 1);
01149 OR(ifElse)
01150 TTEXT("else");
01151 TTEXT("{");
01152 NT2(Actions, 1, 0);
01153 TTEXT("}");
01154 OR(ifElse)
01155 BUILD_APP_NODE("nop", FPOS, 0);
01156 BUILD_NODE(N_ACTIONS, "ACTIONS", FPOS, 1, 1);
01157 BUILD_APP_NODE("nop", FPOS, 0);
01158 BUILD_NODE(N_ACTIONS, "ACTIONS", FPOS, 1, 1);
01159 END_TRY(ifElse)
01160 UNZIP(2);
01161 BUILD_APP_NODE("if", &start, 5);
01162 OR(funcIf)
01163 TTEXT("if");
01164 NT2(Term, rulegen, MIN_PREC);
01165 TTEXT("then");
01166 NT2(Term, 1, MIN_PREC);
01167 BUILD_APP_NODE("nop", FPOS, 0);
01168 TTEXT("else")
01169 NT2(Term, 1, MIN_PREC);
01170 BUILD_APP_NODE("nop", FPOS, 0);
01171 UNZIP(2);
01172 BUILD_APP_NODE("if2", &start, 5);
01173 END_TRY(funcIf)
01174 OR(func)
01175 ABORT(!rulegen);
01176 TRY(whil)
01177 TTEXT("while");
01178 OR(whil)
01179 TTEXT("whileExec");
01180 END_TRY(whil)
01181 TTEXT("(");
01182 NT2(Term, 1, MIN_PREC);
01183 TTEXT(")");
01184 TTEXT("{");
01185 NT2(Actions, 1, 0);
01186 TTEXT("}");
01187 BUILD_APP_NODE("while", &start, 3);
01188 OR(func)
01189 ABORT(!rulegen);
01190 TRY(foreach)
01191 TTEXT("foreach");
01192 OR(foreach)
01193 TTEXT("forEachExec");
01194 END_TRY(foreach)
01195 TTEXT("(");
01196 TTYPE(TK_LOCAL_VAR);
01197 BUILD_NODE(TK_VAR, token->text, &pos, 0, 0);
01198 TRY(foreach2)
01199 TTEXT(")");
01200 TTEXT("{");
01201 NT2(Actions, 1, 0);
01202 TTEXT("}");
01203 BUILD_APP_NODE("foreach", &start, 3);
01204 OR(foreach2)
01205 TTEXT("in");
01206 NT2(Term, 1, MIN_PREC);
01207 TTEXT(")");
01208 TTEXT("{");
01209 NT2(Actions, 1, 0);
01210 TTEXT("}");
01211 BUILD_APP_NODE("foreach2", &start, 4);
01212 END_TRY(foreach2)
01213
01214 OR(func)
01215 ABORT(!rulegen);
01216 TRY(fo)
01217 TTEXT("for");
01218 OR(fo)
01219 TTEXT("forExec");
01220 END_TRY(fo)
01221 TTEXT("(");
01222 NT2(Term, 1, MIN_PREC);
01223 TTEXT(";");
01224 NT2(Term, 1, MIN_PREC);
01225 TTEXT(";");
01226 NT2(Term, 1, MIN_PREC);
01227 TTEXT(")");
01228 TTEXT("{");
01229 NT2(Actions, 1, 0);
01230 TTEXT("}");
01231 BUILD_APP_NODE("for", &start, 5);
01232 OR(func)
01233 ABORT(!rulegen);
01234 TTEXT("remote");
01235 TTEXT("(");
01236 NT2(Term, 1, MIN_PREC);
01237 TTEXT(",");
01238 NT2(Term, 1, MIN_PREC);
01239 TTEXT(")");
01240 TTEXT("{");
01241 char buf[10000];
01242 Label actionsStart = *FPOS;
01243 NT2(Actions, 1, 0);
01244 (void) POP;
01245 (void) POP;
01246 Label actionsFinish = *FPOS;
01247 TTEXT("}");
01248 dupString(e, &actionsStart, actionsFinish.exprloc - actionsStart.exprloc, buf);
01249 BUILD_NODE(TK_STRING, buf, &actionsStart, 0, 0);
01250 BUILD_NODE(TK_STRING, "", &actionsFinish, 0, 0);
01251 BUILD_APP_NODE("remoteExec", &start, 4);
01252 OR(func)
01253 ABORT(!rulegen);
01254 TTEXT("delay");
01255 TTEXT("(");
01256 NT2(Term, 1, MIN_PREC);
01257 TTEXT(")");
01258 TTEXT("{");
01259 char buf[10000];
01260 Label actionsStart = *FPOS;
01261 NT2(Actions, 1, 0);
01262 (void) POP;
01263 (void) POP;
01264 Label actionsFinish = *FPOS;
01265 TTEXT("}");
01266 dupString(e, &actionsStart, actionsFinish.exprloc - actionsStart.exprloc, buf);
01267 BUILD_NODE(TK_STRING, buf, &actionsStart, 0, 0);
01268 BUILD_NODE(TK_STRING, "", &actionsFinish, 0, 0);
01269 BUILD_APP_NODE("delayExec", &start, 3);
01270 OR(func)
01271 ABORT(!rulegen);
01272 TTEXT("let");
01273 NT2(Term, 1, 2);
01274 TTEXT("=");
01275 NT2(Term, 1, MIN_PREC);
01276 TTEXT("in");
01277 NT2(Term, 1, MIN_PREC);
01278 BUILD_APP_NODE("let", &start, 3);
01279 OR(func)
01280 ABORT(!rulegen);
01281 TTEXT("match");
01282 NT2(Term, 1, 2);
01283 TTEXT("with");
01284 int n = 0;
01285 OPTIONAL_BEGIN(semicolon)
01286 TTEXT("|");
01287 OPTIONAL_END(semicolon)
01288 LOOP_BEGIN(cases)
01289 Label cpos = *FPOS;
01290 NT2(Term, 1, MIN_PREC);
01291 TTEXT("=>");
01292 NT2(Term, 1, MIN_PREC);
01293 BUILD_NODE(N_TUPLE, TUPLE, &cpos, 2, 2);
01294 n++;
01295 TRY(vbar)
01296 TTEXT("|");
01297 OR(vbar)
01298 DONE(cases)
01299
01300 END_TRY(vbar);
01301 LOOP_END(cases)
01302 BUILD_APP_NODE("match", &start, n+1);
01303 OR(func)
01304 ABORT(rulegen);
01305 NT1(TermSystemBackwardCompatible, 0);
01306 OR(func)
01307 TTYPE(TK_TEXT);
01308 ABORT(rulegen && isKeyword(token->text));
01309 char *fn = cpStringExt(token->text, context->region);
01310 BUILD_NODE(TK_TEXT, fn, &start, 0, 0);
01311 #ifdef DEBUG_VERBOSE
01312 char err[1024];
01313 generateErrMsg(fn, start.exprloc, start.base, err);
01314 printf("%s, %ld\n", err, start.exprloc);
01315 #endif
01316 TRY(nullary)
01317 TTEXT_LOOKAHEAD("(");
01318 OR(nullary)
01319 TTEXT_LOOKAHEAD("[");
01320 OR(nullary)
01321 Node *n = POP;
01322 BUILD_APP_NODE(n->text, &start, 0);
01323 END_TRY(nullary)
01324 END_TRY(func)
01325 OR(value)
01326 NT1(StringExpression, NULL);
01327 END_TRY(value)
01328 PARSER_FUNC_END(Value)
01329
01330 int nextStringBase2(Pointer *e, char *value, char* delim) {
01331 nextChar(e);
01332 int ch = nextChar(e);
01333 while(ch!=-1) {
01334 if(delim[0] == ch && delim[1] == lookAhead(e, 1)) {
01335 if(delim[0] == delim[1]) {
01336 while(lookAhead(e, 2) == delim[1]) {
01337 *(value++) = delim[0];
01338 nextChar(e);
01339 }
01340 }
01341 *value='\0';
01342 nextChar(e);
01343 nextChar(e);
01344 return 0;
01345 }
01346 *(value++) = ch;
01347 ch = nextChar(e);
01348 }
01349 return -1;
01350
01351 }
01352 /*
01353 * return number of vars or -1 if no string found
01354 */
01355 int nextStringBase(Pointer *e, char *value, char* delim, int consumeDelim, char escape, int vars[]) {
01356 int mode=1; /* 1 string 3 escape */
01357 int nov = 0;
01358 char* value0=value;
01359 *value = lookAhead(e, 0);
01360 value++;
01361 int ch = nextChar(e);
01362 while(ch!=-1) {
01363 *value = ch;
01364 switch(mode) {
01365 case 1:
01366 if(ch ==escape) {
01367 value--;
01368 mode = 3;
01369 } else if(strchr(delim, ch)!=NULL) {
01370 if(consumeDelim) {
01371 value[1]='\0';
01372 trimquotes(value0);
01373 nextChar(e);
01374 } else {
01375 value[0]='\0';
01376 }
01377 vars[nov] = -1;
01378 return nov;
01379 } else if((ch =='*' || ch=='$') &&
01380 isalpha(lookAhead(e, 1))) {
01381 vars[nov++] = value - value0 - 1;
01382 }
01383
01384
01385 break;
01386 case 3:
01387 if(ch=='n') {
01388 *value = '\n';
01389 } else if(ch == 't') {
01390 *value = '\t';
01391 } else if(ch =='r') {
01392 *value = '\r';
01393 } else if(ch =='0') {
01394 *value = '\0';
01395 } else {
01396 *value = ch;
01397 }
01398 mode -= 2;
01399 }
01400 ch = nextChar(e);
01401 value ++;
01402 }
01403 return -1;
01404 }
01405 int nextStringParsed(Pointer *e, char *value, char* deliml, char *delimr, char *delim, int consumeDelim, int vars[]) {
01406 int mode=0; /* level */
01407 int nov = 0;
01408 char* value0=value;
01409 int ch = lookAhead(e, 0);
01410 while(ch!=-1) {
01411 *value = ch;
01412 if(strchr(deliml, ch)!=NULL) {
01413 mode ++;
01414 } else if(mode > 0 && strchr(delimr, ch)!=NULL) {
01415 mode --;
01416 } else if(mode == 0 && strchr(delim, ch)) {
01417 if(consumeDelim) {
01418 value[1]='\0';
01419 trimquotes(value0);
01420 nextChar(e);
01421 } else {
01422 value[0]='\0';
01423 }
01424 vars[nov] = -1;
01425 return nov;
01426 } else if((ch =='*' || ch=='$') &&
01427 isalpha(lookAhead(e, 1))) {
01428 vars[nov++] = value - value0;
01429 }
01430 ch = nextChar(e);
01431 value ++;
01432 }
01433 return -1;
01434 }
01435 int nextString(Pointer *e, char *value, int vars[]) {
01436 return nextStringBase(e, value, "\"", 1, '\\', vars);
01437 }
01438 int nextString2(Pointer *e, char *value, int vars[]) {
01439 return nextStringBase(e, value, "\'", 1, '\\', vars);
01440 }
01441
01442 int getBinaryPrecedence(Token * token) {
01443 int i;
01444 for(i=0;i<num_ops;i++) {
01445 if(new_ops[i].arity==2 && strcmp(new_ops[i].string,token->text)==0) {
01446 return new_ops[i].prec;
01447 }
01448 }
01449 return -1;
01450 }
01451 int getUnaryPrecedence(Token * token) {
01452 int i;
01453 for(i=0;i<num_ops;i++) {
01454 if(new_ops[i].arity==1 && strcmp(new_ops[i].string,token->text)==0) {
01455 return new_ops[i].prec;
01456 }
01457 }
01458 return -1;
01459 }
01460 int isUnaryOp(Token *token) {
01461 int i;
01462 for (i=0;i<num_ops;i++) {
01463 if (strcmp(token->text, new_ops[i].string) == 0) {
01464 if(new_ops[i].arity == 1) return 1;
01465 }
01466 }
01467 return 0;
01468 }
01469 int isBinaryOp(Token *token) {
01470 int i;
01471 for (i=0;i<num_ops;i++) {
01472 if (strcmp(token->text, new_ops[i].string) == 0) {
01473 if(new_ops[i].arity == 2) return 1;
01474 }
01475 }
01476 return 0;
01477 }
01478 int isOp(char *token) {
01479 int i;
01480 for (i=0;i<num_ops;i++) {
01481 if (strcmp(token, new_ops[i].string) == 0) {
01482 return 1;
01483 }
01484 }
01485 return 0;
01486 }
01487 char* trim(char* str) {
01488 char* trimmed = str;
01489 while(*trimmed =='\t' || *trimmed==' ') {
01490 trimmed ++;
01491 }
01492 int l = strlen(trimmed)-1;
01493 while(l>=0 && (trimmed[l] =='\t' || trimmed[l]==' ')) {
01494 l--;
01495 }
01496 trimmed[l+1] = '\0';
01497 return trimmed;
01498
01499 }
01500 void trimquotes(char *string) {
01501 int len = strlen(string)-2;
01502 memmove(string, string+1, len*sizeof(char));
01503 string[len]='\0';
01504 }
01505
01506 void printTree(Node *n, int indent) {
01507 printIndent(indent);
01508 char buf[128], buf2[128];
01509 if(getNodeType(n) >= T_UNSPECED && getNodeType(n) <= T_TYPE ) {
01510 typeToString(n, NULL, buf, 128);
01511 printf("%s:%d\n", buf, getNodeType(n));
01512 return;
01513 } else if(getNodeType(n) >= TC_LT && getNodeType(n) <= TC_SET) {
01514 printf("%s:%d\n",n->text, getNodeType(n));
01515 } else {
01516 if(n->coercionType!=NULL) {
01517 typeToString(n->coercionType, NULL, buf, 128);
01518 } else {
01519 buf[0] = '\0';
01520 }
01521 if(n->exprType!=NULL) {
01522 typeToString(n->exprType, NULL, buf2, 128);
01523 } else {
01524 buf2[0] = '\0';
01525 }
01526 char iotype[128];
01527 strcpy(iotype, "");
01528 if(getIOType(n) & IO_TYPE_INPUT) {
01529 strcat(iotype, "i");
01530 }
01531 if(getIOType(n) & IO_TYPE_OUTPUT) {
01532 strcat(iotype, "o");
01533 }
01534 if(getIOType(n) & IO_TYPE_DYNAMIC) {
01535 strcat(iotype, "d");
01536 }
01537 if(getIOType(n) & IO_TYPE_EXPRESSION) {
01538 strcat(iotype, "e");
01539 }
01540 if(getIOType(n) & IO_TYPE_ACTIONS) {
01541 strcat(iotype, "a");
01542 }
01543 printf("%s:%d %s => %s(option=%d)[%s]\n",n->text, getNodeType(n), buf2, buf, n->option, iotype);
01544 }
01545 int i;
01546 for(i=0;i<n->degree;i++) {
01547 printTree(n->subtrees[i],indent+1);
01548 }
01549
01550 }
01551 #define PRINT(p, s, f, d) snprintf(*p, *s, f, d);*s -= strlen(*p); *p += strlen(*p);
01552 void patternToString(char **p, int *s, int indent, int prec, Node *n) {
01553 switch(getNodeType(n)) {
01554 case N_APPLICATION:
01555 if(getNodeType(n->subtrees[0]) == TK_TEXT) {
01556 char *fn = n->subtrees[0]->text;
01557 Token t;
01558 strcpy(t.text, fn);
01559 if(isBinaryOp(&t)) {
01560 int opPrec = getBinaryPrecedence(&t);
01561 if(opPrec < prec) {
01562 PRINT(p, s, "%s", "(");
01563 }
01564 patternToString(p, s, indent, prec, n->subtrees[1]->subtrees[0]);
01565 PRINT(p, s, " %s ", fn);
01566 patternToString(p, s, indent, prec+1, n->subtrees[1]->subtrees[1]);
01567 if(opPrec < prec) {
01568 PRINT(p, s, "%s", ")");
01569 }
01570 } else {
01571 patternToString(p, s, indent, MIN_PREC, n->subtrees[0]);
01572 if(getNodeType(n->subtrees[1]) != N_TUPLE || n->subtrees[1]->degree != 0) {
01573 patternToString(p, s, indent, MIN_PREC, n->subtrees[1]);
01574 }
01575 }
01576 } else {
01577 PRINT(p, s, "%s", "<unsupported>");
01578 }
01579 break;
01580 case N_TUPLE:
01581 PRINT(p, s, "%s", "(");
01582 int i;
01583 for(i=0;i<n->degree;i++) {
01584 if(i!=0) {
01585 PRINT(p, s, "%s", ",");
01586 }
01587 patternToString(p, s, indent, MIN_PREC, n->subtrees[i]);
01588 }
01589 PRINT(p, s, "%s", ")");
01590 break;
01591 case TK_BOOL:
01592 case TK_DOUBLE:
01593 case TK_INT:
01594 case TK_VAR:
01595 case TK_TEXT:
01596 PRINT(p, s, "%s", n->text);
01597 break;
01598 case TK_STRING:
01599 PRINT(p, s, "%s", "\"");
01600 unsigned int k;
01601 for(k=0;k<strlen(n->text);k++) {
01602 switch(n->text[k]) {
01603 case '\t':
01604 PRINT(p, s, "%s", "\\t");
01605 break;
01606 case '\n':
01607 PRINT(p, s, "%s", "\\n");
01608 break;
01609 case '\r':
01610 PRINT(p, s, "%s", "\\r");
01611 break;
01612 case '$':
01613 case '*':
01614 case '\\':
01615 case '\"':
01616 case '\'':
01617 PRINT(p, s, "%s", "\\");
01618 PRINT(p, s, "%c", n->text[k]);
01619 break;
01620 default:
01621 PRINT(p, s, "%c", n->text[k]);
01622
01623 }
01624 }
01625 PRINT(p, s, "%s", "\"");
01626 break;
01627 default:
01628 PRINT(p, s, "%s", "<unsupported>");
01629 }
01630 }
01631 void termToString(char **p, int *s, int indent, int prec, Node *n) {
01632 switch(getNodeType(n)) {
01633 case N_ACTIONS_RECOVERY:
01634 actionsToString(p, s, indent, n->subtrees[0], n->subtrees[1]);
01635 break;
01636 case N_APPLICATION:
01637 if(getNodeType(n->subtrees[0]) == TK_TEXT) {
01638 char *fn = n->subtrees[0]->text;
01639 if(strcmp(fn, "if") == 0) {
01640 PRINT(p, s, "%s", "if (");
01641 termToString(p, s, indent, MIN_PREC, n->subtrees[1]->subtrees[0]);
01642 PRINT(p, s, "%s", ") ");
01643 actionsToString(p, s, indent, n->subtrees[1]->subtrees[1], n->subtrees[1]->subtrees[3]);
01644 PRINT(p, s, "%s", " else ");
01645 actionsToString(p, s, indent, n->subtrees[1]->subtrees[2], n->subtrees[1]->subtrees[4]);
01646 break;
01647 }
01648 if(strcmp(fn, "if2") == 0) {
01649 PRINT(p, s, "%s", "if ");
01650 termToString(p, s, indent, MIN_PREC, n->subtrees[1]->subtrees[0]);
01651 PRINT(p, s, "%s", " then ");
01652 termToString(p, s, indent, MIN_PREC, n->subtrees[1]->subtrees[1]);
01653 PRINT(p, s, "%s", " else ");
01654 termToString(p, s, indent, MIN_PREC, n->subtrees[1]->subtrees[2]);
01655 break;
01656 }
01657 if(strcmp(fn, "while") == 0) {
01658 PRINT(p, s, "%s", "while (");
01659 termToString(p, s, indent, MIN_PREC, n->subtrees[1]->subtrees[0]);
01660 PRINT(p, s, "%s", ") ");
01661 actionsToString(p, s, indent, n->subtrees[1]->subtrees[1], n->subtrees[1]->subtrees[2]);
01662 break;
01663 }
01664 if(strcmp(fn, "foreach") == 0) {
01665 PRINT(p, s, "%s", "foreach (");
01666 termToString(p, s, indent, MIN_PREC, n->subtrees[1]->subtrees[0]);
01667 PRINT(p, s, "%s", ") ");
01668 actionsToString(p, s, indent, n->subtrees[1]->subtrees[1], n->subtrees[1]->subtrees[2]);
01669 break;
01670 }
01671 if(strcmp(fn, "foreach2") == 0) {
01672 PRINT(p, s, "%s", "foreach (");
01673 termToString(p, s, indent, MIN_PREC, n->subtrees[1]->subtrees[0]);
01674 PRINT(p, s, "%s", " in ");
01675 termToString(p, s, indent, MIN_PREC, n->subtrees[1]->subtrees[1]);
01676 PRINT(p, s, "%s", ") ");
01677 actionsToString(p, s, indent, n->subtrees[1]->subtrees[2], n->subtrees[1]->subtrees[3]);
01678 break;
01679 }
01680 if(strcmp(fn, "for") == 0) {
01681 PRINT(p, s, "%s", "for (");
01682 termToString(p, s, indent, MIN_PREC, n->subtrees[1]->subtrees[0]);
01683 PRINT(p, s, "%s", ";");
01684 termToString(p, s, indent, MIN_PREC, n->subtrees[1]->subtrees[1]);
01685 PRINT(p, s, "%s", ";");
01686 termToString(p, s, indent, MIN_PREC, n->subtrees[1]->subtrees[2]);
01687 PRINT(p, s, "%s", ") ");
01688 actionsToString(p, s, indent, n->subtrees[1]->subtrees[3], n->subtrees[1]->subtrees[4]);
01689 break;
01690 }
01691 if(strcmp(fn, "let") == 0) {
01692 PRINT(p, s, "%s", "let ");
01693 termToString(p, s, indent, MIN_PREC, n->subtrees[1]->subtrees[0]);
01694 PRINT(p, s, "%s", " = ");
01695 termToString(p, s, indent, MIN_PREC, n->subtrees[1]->subtrees[1]);
01696 PRINT(p, s, "%s", " in ");
01697 termToString(p, s, indent, MIN_PREC, n->subtrees[1]->subtrees[2]);
01698 break;
01699 }
01700 if(strcmp(fn, "match") == 0) {
01701 PRINT(p, s, "%s", "match ");
01702 termToString(p, s, indent, MIN_PREC, N_APP_ARG(n, 0));
01703 PRINT(p, s, "%s", " with");
01704 int i;
01705 for(i=1;i<N_APP_ARITY(n);i++) {
01706 PRINT(p, s, "%s", "\n");
01707 indentToString(p, s, indent + 1);
01708 PRINT(p, s, "%s", "| ");
01709 patternToString(p, s, indent + 1, MIN_PREC, N_APP_ARG(n, i)->subtrees[0]);
01710 PRINT(p, s, "%s", " => ");
01711 termToString(p, s, indent + 1, MIN_PREC, N_APP_ARG(n, i)->subtrees[1]);
01712 }
01713 break;
01714 }
01715 if(strcmp(fn, "assign") == 0) {
01716 patternToString(p, s, indent, MIN_PREC, n->subtrees[1]->subtrees[0]);
01717 PRINT(p, s, "%s", " = ");
01718 termToString(p, s, indent, MIN_PREC, n->subtrees[1]->subtrees[1]);
01719 break;
01720 }
01721 Token t;
01722 strcpy(t.text, fn);
01723 if(isBinaryOp(&t)) {
01724 int opPrec = getBinaryPrecedence(&t);
01725 if(opPrec < prec) {
01726 PRINT(p, s, "%s", "(");
01727 }
01728 termToString(p, s, indent, prec, n->subtrees[1]->subtrees[0]);
01729 PRINT(p, s, " %s ", fn);
01730 termToString(p, s, indent, prec+1, n->subtrees[1]->subtrees[1]);
01731 if(opPrec < prec) {
01732 PRINT(p, s, "%s", ")");
01733 }
01734 break;
01735 }
01736 }
01737 termToString(p, s, indent, MIN_PREC, n->subtrees[0]);
01738 termToString(p, s, indent, MIN_PREC, n->subtrees[1]);
01739 break;
01740 case N_TUPLE:
01741 PRINT(p, s, "%s", "(");
01742 int i;
01743 for(i=0;i<n->degree;i++) {
01744 if(i!=0) {
01745 PRINT(p, s, "%s", ",");
01746 }
01747 termToString(p, s, indent, MIN_PREC, n->subtrees[i]);
01748 }
01749 PRINT(p, s, "%s", ")");
01750 break;
01751 case TK_BOOL:
01752 case TK_DOUBLE:
01753 case TK_INT:
01754 case TK_VAR:
01755 case TK_TEXT:
01756 PRINT(p, s, "%s", n->text);
01757 break;
01758 case TK_STRING:
01759 PRINT(p, s, "%s", "\"");
01760 unsigned int k;
01761 for(k=0;k<strlen(n->text);k++) {
01762 switch(n->text[k]) {
01763 case '\t':
01764 PRINT(p, s, "%s", "\\t");
01765 break;
01766 case '\n':
01767 PRINT(p, s, "%s", "\\n");
01768 break;
01769 case '\r':
01770 PRINT(p, s, "%s", "\\r");
01771 break;
01772 case '$':
01773 case '*':
01774 case '\\':
01775 case '\"':
01776 case '\'':
01777 PRINT(p, s, "%s", "\\");
01778 PRINT(p, s, "%c", n->text[k]);
01779 break;
01780 default:
01781 PRINT(p, s, "%c", n->text[k]);
01782
01783 }
01784
01785 }
01786 PRINT(p, s, "%s", "\"");
01787 break;
01788 default:
01789 PRINT(p, s, "%s", "<unsupported>");
01790 }
01791 }
01792 void indentToString(char **p, int *s, int indent) {
01793 int i;
01794 for(i=0;i<indent;i++) {
01795 PRINT(p, s, "%s", " ");
01796 }
01797
01798 }
01799 void actionsToString(char **p, int *s, int indent, Node *na, Node *nr) {
01800 int n = na->degree;
01801
01802 int i;
01803 PRINT(p, s, "%s", "{\n");
01804 for(i=0;i<n;i++) {
01805 indentToString(p, s, indent+1);
01806 termToString(p, s, indent+1, MIN_PREC, na->subtrees[i]);
01807 if(nr!=NULL && i<nr->degree && (getNodeType(nr->subtrees[i])!=N_APPLICATION || strcmp(nr->subtrees[i]->subtrees[0]->text, "nop")!=0)) {
01808 PRINT(p, s, "%s", ":::");
01809 termToString(p, s, indent+1, MIN_PREC, nr->subtrees[i]);
01810 }
01811 if((*p)[-1]!='}')
01812 PRINT(p, s, "%s", ";");
01813 PRINT(p, s, "%s", "\n");
01814 }
01815 indentToString(p, s, indent);
01816 PRINT(p, s, "%s", "}");
01817 }
01818
01819 void metadataToString(char **p, int *s, int indent, Node *nm) {
01820 int n = nm->degree;
01821 int i;
01822 for(i=0;i<n;i++) {
01823 indentToString(p, s, indent);
01824 PRINT(p, s, "%s", "@(");
01825 termToString(p, s, indent, MIN_PREC, nm->subtrees[i]->subtrees[0]);
01826 PRINT(p, s, "%s", ", ");
01827 termToString(p, s, indent, MIN_PREC, nm->subtrees[i]->subtrees[1]);
01828 PRINT(p, s, "%s", ", ");
01829 termToString(p, s, indent, MIN_PREC, nm->subtrees[i]->subtrees[2]);
01830 PRINT(p, s, "%s", ")\n");
01831 }
01832 }
01833
01834 void ruleNameToString(char **p, int *s, int indent, Node *rn) {
01835 PRINT(p, s, "%s", rn->text);
01836 PRINT(p, s, "%s", "(");
01837 int i;
01838 for(i=0;i<rn->subtrees[0]->degree;i++) {
01839 if(i!=0) {
01840 PRINT(p, s, "%s", ",");
01841 }
01842 patternToString(p, s, indent, MIN_PREC, rn->subtrees[0]->subtrees[i]);
01843 }
01844 PRINT(p, s, "%s", ")");
01845 }
01846 void typeToStringParser(char **p, int *s, int indent, int lifted, ExprType *type) {
01847 ExprType *etype = type;
01848
01849 if(getIOType(etype) == (IO_TYPE_INPUT | IO_TYPE_OUTPUT)) {
01850 PRINT(p, s, "%s ", "input output");
01851 } else if(getIOType(etype) == IO_TYPE_OUTPUT) {
01852 PRINT(p, s, "%s ", "output");
01853 } else if(getIOType(etype) == IO_TYPE_DYNAMIC) {
01854 PRINT(p, s, "%s ", "dynamic");
01855 } else if(getIOType(etype) == IO_TYPE_ACTIONS) {
01856 PRINT(p, s, "%s ", "actions");
01857 } else if(getIOType(etype) == IO_TYPE_EXPRESSION) {
01858 PRINT(p, s, "%s ", "expression");
01859 }
01860 if(getNodeType(etype) == T_VAR) {
01861 PRINT(p, s, "%s", etype->text);
01862 if(T_VAR_NUM_DISJUNCTS(type)!=0) {
01863 PRINT(p, s, " %s", "{");
01864 int i;
01865 for(i=0;i<T_VAR_NUM_DISJUNCTS(type);i++) {
01866 typeToStringParser(p, s, indent, 0, T_VAR_DISJUNCT(type, i));
01867 PRINT(p, s, "%s", " ");
01868 }
01869 PRINT(p, s, "%s", "}");
01870 }
01871 } else if(getNodeType(etype) == T_CONS) {
01872 if(strcmp(etype->text, FUNC) == 0) {
01873
01874 typeToStringParser(p, s, indent, 1, T_CONS_TYPE_ARG(etype, 0));
01875 if(getVararg(type) == OPTION_VARARG_OPTIONAL) {
01876 PRINT(p, s, " %s", "?");
01877 } else if(getVararg(type) == OPTION_VARARG_STAR) {
01878 PRINT(p, s, " %s", "*");
01879 } else if(getVararg(type) == OPTION_VARARG_PLUS) {
01880 PRINT(p, s, " %s", "+");
01881 }
01882 PRINT(p, s, " %s ", "->");
01883 typeToStringParser(p, s, indent, 0, T_CONS_TYPE_ARG(etype, 1));
01884
01885 } else {
01886 PRINT(p, s, "%s", T_CONS_TYPE_NAME(etype));
01887 int i;
01888 if(T_CONS_ARITY(etype) != 0) {
01889 PRINT(p, s, "%s", "(");
01890 for(i=0;i<T_CONS_ARITY(etype);i++) {
01891 if(i!=0) {
01892 PRINT(p, s, "%s ", ",");
01893 }
01894 typeToStringParser(p, s, indent, 0, T_CONS_TYPE_ARG(etype, i));
01895 }
01896 PRINT(p, s, "%s", ")");
01897 }
01898 }
01899 } else if(getNodeType(etype) == T_FLEX) {
01900 PRINT(p, s, "%s ", typeName_Parser(getNodeType(etype)));
01901 typeToStringParser(p, s, indent, 0, etype->subtrees[0]);
01902 } else if(getNodeType(etype) == T_FIXD) {
01903 PRINT(p, s, "%s ", typeName_Parser(getNodeType(etype)));
01904 typeToStringParser(p, s, indent, 0, etype->subtrees[0]);
01905 PRINT(p, s, " %s ", "=>");
01906 typeToStringParser(p, s, indent, 0, etype->subtrees[1]);
01907 } else if(getNodeType(etype) == T_TUPLE) {
01908 if(T_CONS_ARITY(etype) == 0) {
01909 PRINT(p, s, "%s", "unit");
01910 } else {
01911 if(T_CONS_ARITY(etype) == 1 && !lifted) {
01912 PRINT(p, s, "%s", "<");
01913 }
01914 int i;
01915 for(i=0;i<T_CONS_ARITY(etype);i++) {
01916 if(i!=0) {
01917 PRINT(p, s, " %s ", "*");
01918 }
01919 typeToStringParser(p, s, indent, 0, T_CONS_TYPE_ARG(etype, i));
01920 }
01921 if(T_CONS_ARITY(etype) == 1 && !lifted) {
01922 PRINT(p, s, "%s", ">");
01923 }
01924 }
01925 } else if(getNodeType(etype) == T_IRODS) {
01926 PRINT(p, s, "`%s`", etype->text);
01927 } else {
01928 PRINT(p, s, "%s", typeName_Parser(getNodeType(etype)));
01929 }
01930
01931 }
01932
01933 void ruleToString(char *buf, int size, RuleDesc *rd) {
01934 Node *node = rd->node;
01935 char **p = &buf;
01936 int *s = &size;
01937 Node *subt = NULL;
01938 switch(rd->ruleType) {
01939 case RK_REL:
01940 ruleNameToString(p, s, 0, node->subtrees[0]);
01941
01942 int indent;
01943 subt = node->subtrees[1];
01944 while(getNodeType(subt) == N_TUPLE && subt->degree == 1) {
01945 subt = subt->subtrees[0];
01946 }
01947
01948 PRINT(p, s, "%s", " ");
01949 if(getNodeType(subt) != TK_BOOL ||
01950 strcmp(subt->text, "true") != 0) {
01951 PRINT(p, s, "%s", "{\n");
01952 indentToString(p, s, 1);
01953 PRINT(p, s, "%s", "on ");
01954 termToString(p, s, 1, MIN_PREC, node->subtrees[1]);
01955 PRINT(p, s, "%s", " ");
01956 indent = 1;
01957 } else {
01958 indent = 0;
01959 }
01960 actionsToString(p, s, indent, node->subtrees[2], node->subtrees[3]);
01961 if(indent == 1) {
01962 PRINT(p, s, "%s", "\n");
01963 indentToString(p, s, 1);
01964 metadataToString(p, s, 0, node->subtrees[4]);
01965 PRINT(p, s, "%s", "}\n");
01966 } else {
01967 PRINT(p, s, "%s", "\n");
01968 metadataToString(p, s, 0, node->subtrees[4]);
01969 }
01970 break;
01971 case RK_FUNC:
01972 ruleNameToString(p, s, 0, node->subtrees[0]);
01973 PRINT(p, s, "%s", " = ");
01974 termToString(p, s, 1, MIN_PREC, node->subtrees[2]);
01975 PRINT(p, s, "%s", "\n");
01976 metadataToString(p, s, 0, node->subtrees[4]);
01977 break;
01978 case RK_CONSTRUCTOR:
01979 PRINT(p, s, "constructor %s", node->subtrees[0]->text);
01980 PRINT(p, s, "%s", " : ");
01981 typeToStringParser(p, s, 0, 0, node->subtrees[1]);
01982 PRINT(p, s, "%s", "\n");
01983
01984 break;
01985 case RK_DATA:
01986 PRINT(p, s, "%s ", "data");
01987 ruleNameToString(p, s, 0, node->subtrees[0]);
01988 PRINT(p, s, "%s", "\n");
01989 break;
01990 case RK_EXTERN:
01991 PRINT(p, s, "%s : ", node->subtrees[0]->text);
01992 typeToStringParser(p, s, 0, 0, node->subtrees[1]);
01993 PRINT(p, s, "%s", "\n");
01994 break;
01995
01996
01997 }
01998
01999 }
02000
02001 void functionApplicationToString(char *buf, int size, char *fn, Node **args, int n) {
02002 char **p = &buf;
02003 int *s = &size;
02004 PRINT(p, s, "%s(", fn);
02005 int i;
02006 char *res;
02007 for(i=0;i<n;i++) {
02008 switch(getNodeType(args[i])) {
02009 case N_VAL:
02010 res = convertResToString(args[i]);
02011 PRINT(p, s, "%s", res);
02012 free(res);
02013 break;
02014 case N_ACTIONS:
02015 actionsToString(p, s, 0, args[i], NULL);
02016 break;
02017 default:
02018 termToString(p, s, 0, MIN_PREC, args[i]);
02019 }
02020 if(i != n-1) {
02021 PRINT(p, s, "%s", ", ");
02022 }
02023 }
02024 PRINT(p, s, "%s", ")");
02025 return;
02026 }
02027
02028 void printTreeDeref(Node *n, int indent, Hashtable *var_types, Region *r) {
02029 printIndent(indent);
02030 printf("%s:%d->",n->text, getNodeType(n));
02031 printType(n->coercionType, var_types);
02032 printf("\n");
02033 int i;
02034 for(i=0;i<n->degree;i++) {
02035 printTreeDeref(n->subtrees[i],indent+1, var_types, r);
02036 }
02037
02038 }
02039
02040 void printIndent(int n) {
02041 int i;
02042 for(i=0;i<n;i++) {
02043 printf("\t");
02044 }
02045 }
02046
02047 int eqExprNodeSyntactic(Node *a, Node *b) {
02048 if(getNodeType(a) == getNodeType(b) &&
02049 strcmp(a->text, b->text) == 0 &&
02050 a->degree == b->degree) {
02051 int i;
02052 for(i=0;i<a->degree;i++) {
02053 if(!eqExprNodeSyntactic(a->subtrees[i], b->subtrees[i])) {
02054 return 0;
02055 }
02056 }
02057 }
02058 return 1;
02059 }
02060 int eqExprNodeSyntacticVarMapping(Node *a, Node *b, Hashtable *varMapping ) {
02061 char *val;
02062 if(getNodeType(a) == TK_VAR && getNodeType(b) == TK_VAR &&
02063 (val = (char *)lookupFromHashTable(varMapping, a->text))!=NULL &&
02064 strcmp(val, b->text) == 0) {
02065 return 1;
02066 }
02067 if(getNodeType(a) == getNodeType(b) &&
02068 strcmp(a->text, b->text) == 0 &&
02069 a->degree == b->degree) {
02070 int i;
02071 for(i=0;i<a->degree;i++) {
02072 if(!eqExprNodeSyntactic(a->subtrees[i], b->subtrees[i])) {
02073 return 0;
02074 }
02075 }
02076 }
02077 return 1;
02078 }
02079
02080 StringList *getVarNamesInExprNode(Node *expr, Region *r) {
02081 return getVarNamesInExprNodeAux(expr, NULL, r);
02082 }
02083
02084 StringList *getVarNamesInExprNodeAux(Node *expr, StringList *vars, Region *r) {
02085 int i;
02086 switch(getNodeType(expr)) {
02087 case TK_VAR:
02088 if(expr->text[0] == '*') {
02089 StringList *nvars = (StringList*)region_alloc(r, sizeof(StringList));
02090 nvars->next = vars;
02091 nvars->str = expr->text;
02092 return nvars;
02093 }
02094
02095 default:
02096 for(i =0;i<expr->degree;i++) {
02097 vars = getVarNamesInExprNodeAux(expr->subtrees[i], vars, r);
02098 }
02099 return vars;
02100 }
02101 }
02102
02103
02104
02105 void nextChars(Pointer *p, int len) {
02106 int i;
02107 for(i=0;i<len;i++) {
02108 nextChar(p);
02109 }
02110 }
02111
02112
02113
02114
02115 int nextChar(Pointer *p) {
02116 if(p->isFile) {
02117 int ch = lookAhead(p, 1);
02118
02119 p->p++;
02120
02121 return ch;
02122 } else {
02123 if(p->strbuf[p->strp] == '\0') {
02124 return -1;
02125 }
02126 int ch = p->strbuf[++p->strp];
02127 if(ch == '\0') {
02128 ch = -1;
02129 }
02130 return ch;
02131 }
02132 }
02133
02134 Pointer *newPointer(FILE *fp, char *ruleBaseName) {
02135 Pointer *e = (Pointer *)malloc(sizeof(Pointer));
02136 initPointer(e, fp, ruleBaseName);
02137 return e;
02138 }
02139 Pointer *newPointer2(char* buf) {
02140 Pointer *e = (Pointer *)malloc(sizeof(Pointer));
02141 initPointer2(e, buf);
02142
02143 return e;
02144 }
02145 void deletePointer(Pointer* buf) {
02146 if(buf->isFile) {
02147 fclose(buf->fp);
02148 }
02149 free(buf->base);
02150 free(buf);
02151
02152 }
02153
02154 void initPointer(Pointer *p, FILE* fp, char* ruleBaseName ) {
02155 fseek(fp, 0, SEEK_SET);
02156 p->fp = fp;
02157 p->fpos = 0;
02158 p->len = 0;
02159 p->p = 0;
02160 p->isFile = 1;
02161 p->base = (char *)malloc(strlen(ruleBaseName)+2);
02162 p->base[0] = 'f';
02163 strcpy(p->base + 1, ruleBaseName);
02164 }
02165
02166 void initPointer2(Pointer *p, char *buf) {
02167 p->strbuf = buf;
02168 p->strlen = strlen(buf);
02169 p->strp = 0;
02170 p->isFile = 0;
02171 p->base = (char *)malloc(strlen(buf)+2);
02172 p->base[0] = 's';
02173 strcpy(p->base + 1, buf);
02174 }
02175
02176 void readToBuffer(Pointer *p) {
02177 if(p->isFile) {
02178 unsigned int move = (p->len+1)/2;
02179 move = move > p->p? p->p : move;
02180 int startpos = p->len - move;
02181 int load = POINTER_BUF_SIZE - startpos;
02182
02183 memmove(p->buf,p->buf+move,startpos*sizeof(char));
02184
02185 int count = fread(p->buf+startpos, sizeof(char), load, p->fp);
02186 p->len = startpos + count;
02187 p->p -= move;
02188 p->fpos += move * sizeof(char);
02189 } else {
02190 }
02191 }
02192
02193 void seekInFile(Pointer *p, unsigned long x) {
02194 if(p -> isFile) {
02195 if(p->fpos < x * sizeof(char) || p->fpos + p->len >= x * sizeof(char)) {
02196 fseek(p->fp, x * sizeof(char), SEEK_SET);
02197 clearBuffer(p);
02198 p->fpos = x * sizeof(char);
02199 readToBuffer(p);
02200 } else {
02201 p->p = x * sizeof(char) - p->fpos;
02202 }
02203 } else {
02204 p->strp = x;
02205 }
02206 }
02207
02208 void clearBuffer(Pointer *p) {
02209 if(p->isFile) {
02210 p->fpos += p->len * sizeof(char);
02211 p->len = p->p = 0;
02212 } else {
02213 }
02214 }
02215
02216
02217 int dupString(Pointer *p, Label * start, int n, char *buf) {
02218 if(p->isFile) {
02219 Label curr;
02220 getFPos(&curr, p, NULL);
02221 seekInFile(p, start->exprloc);
02222 int len = 0;
02223 int ch;
02224 while(len < n && (ch=lookAhead(p, 0)) != -1) {
02225 buf[len++] = (char) ch;
02226 nextChar(p);
02227 }
02228 buf[len] = '\0';
02229 seekInFile(p, curr.exprloc);
02230 return len;
02231 } else {
02232 int len = strlen(p->strbuf + start->exprloc);
02233 len = len > n ? n : len;
02234 memcpy(buf, p->strbuf + start->exprloc, len * sizeof(char));
02235 buf[len] = '\0';
02236 return len;
02237 }
02238 }
02239
02240 int dupLine(Pointer *p, Label * start, int n, char *buf) {
02241 Label pos;
02242 getFPos(&pos, p, NULL);
02243 seekInFile(p, 0);
02244 int len = 0;
02245 int i = 0;
02246 int ch = lookAhead(p, 0);
02247 while(ch != -1) {
02248 if(ch=='\n') {
02249 if(i<start->exprloc)
02250 len = 0;
02251 else {
02252 break;
02253 }
02254 } else {
02255 buf[len] = ch;
02256 len++;
02257 if(len == n - 1) {
02258 break;
02259 }
02260 }
02261 i++;
02262 ch = nextChar(p);
02263 }
02264 buf[len] = '\0';
02265 seekInFile(p, pos.exprloc);
02266 return len;
02267 }
02268
02269 void getCoor(Pointer *p, Label * errloc, int coor[2]) {
02270 Label pos;
02271 getFPos(&pos, p, NULL);
02272 seekInFile(p, 0);
02273 coor[0] = coor[1] = 0;
02274 int i;
02275 char ch = lookAhead(p, 0);
02276 for(i =0;i<errloc->exprloc;i++) {
02277 if(ch=='\n') {
02278 coor[0]++;
02279 coor[1] = 0;
02280 } else {
02281 coor[1]++;
02282 }
02283 ch = nextChar(p);
02284
02285
02286
02287 }
02288 seekInFile(p, pos.exprloc);
02289 }
02290
02291 int getLineRange(Pointer *p, int line, rodsLong_t range[2]) {
02292 Label pos;
02293 getFPos(&pos, p, NULL);
02294 seekInFile(p, 0);
02295 Label l;
02296 range[0] = range[1] = 0;
02297 int i = 0;
02298 int ch = lookAhead(p, 0);
02299 while (i < line && ch != -1) {
02300 if(ch=='\n') {
02301 i++;
02302 }
02303 ch = nextChar(p);
02304
02305
02306
02307 }
02308 if(ch == -1) {
02309 return -1;
02310 }
02311 range[0] = getFPos(&l, p, NULL)->exprloc;
02312 while (i == line && ch != -1) {
02313 if(ch=='\n') {
02314 i++;
02315 }
02316 ch = nextChar(p);
02317
02318
02319
02320 }
02321 range[1] = getFPos(&l, p, NULL)->exprloc;
02322 seekInFile(p, pos.exprloc);
02323 return 0;
02324 }
02325
02326 Label *getFPos(Label *l, Pointer *p, ParserContext *context) {
02327 if(context == NULL || context->tqtop == context->tqp) {
02328 if(p->isFile) {
02329 l->exprloc = p->fpos/sizeof(char) + p->p;
02330 } else {
02331 l->exprloc = p->strp;
02332 }
02333 } else {
02334 l->exprloc = context->tokenQueue[context->tqp].exprloc;
02335 }
02336 l->base = p->base;
02337 return l;
02338 }
02339
02340 int lookAhead(Pointer *p, unsigned int n) {
02341 if(p->isFile) {
02342 if(p->p+n >= p->len) {
02343 readToBuffer(p);
02344 if(p->p+n >= p->len) {
02345 return -1;
02346 }
02347 }
02348 return (int)(p->buf[p->p+n]);
02349 } else {
02350 if(n+p->strp >= p->strlen) {
02351 return -1;
02352 }
02353 return (int)p->strbuf[p->strp+n];
02354 }
02355
02356 }
02357
02358
02359 char *functionParameters(char *e, char *value) {
02360 int mode=0;
02361 int l0 = 0;
02362 while(*e!=0) {
02363 *value = *e;
02364 switch(mode) {
02365 case 0:
02366
02367 switch(*e) {
02368 case '(':
02369 l0++;
02370 break;
02371 case '\"':
02372 mode = 1;
02373 break;
02374 case '\'':
02375 mode = 2;
02376 break;
02377 case ')':
02378 l0--;
02379 if(l0==0) {
02380 value[1]='\0';
02381 return e+1;
02382 }
02383 }
02384 break;
02385 case 1:
02386 switch(*e) {
02387 case '\\':
02388 mode = 3;
02389 break;
02390 case '\"':
02391 mode = 0;
02392 }
02393 break;
02394 case 2:
02395 switch(*e) {
02396 case '\\':
02397 mode = 4;
02398 break;
02399 case '\'':
02400 mode = 0;
02401 }
02402 break;
02403 case 3:
02404 case 4:
02405 mode -= 2;
02406 }
02407 e++; value ++;
02408 }
02409 *value=0;
02410 return e;
02411 }
02412 char *nextStringString(char *e, char *value) {
02413 int mode=1;
02414 char* e0=e;
02415 char* value0=value;
02416 *value = *e;
02417 value++;
02418 e++;
02419 while(*e!=0) {
02420 *value = *e;
02421 switch(mode) {
02422 case 1:
02423 switch(*e) {
02424 case '\\':
02425 value--;
02426 mode = 3;
02427 break;
02428 case '\"':
02429 value[1]='\0';
02430 trimquotes(value0);
02431 return e+1;
02432 }
02433 break;
02434 case 3:
02435 mode -= 2;
02436 }
02437 e++; value ++;
02438 }
02439 return e0;
02440 }
02441 char *nextString2String(char *e, char *value) {
02442 int mode=1;
02443 char* e0=e;
02444 char* value0 = value;
02445 *value = *e;
02446 value ++;
02447 e++;
02448 while(*e!=0) {
02449 *value = *e;
02450 switch(mode) {
02451 case 1:
02452 switch(*e) {
02453 case '\\':
02454 value--;
02455 mode = 3;
02456 break;
02457 case '\'':
02458 value[1]='\0';
02459 trimquotes(value0);
02460 return e+1;
02461 }
02462 break;
02463 case 3:
02464 mode -= 2;
02465 }
02466 e++; value ++;
02467 }
02468 return e0;
02469 }
02470
02471
02472 char * nextRuleSection(char* buf, char* value) {
02473 char* e=buf;
02474 int mode=0;
02475 while(*e!=0) {
02476 *value = *e;
02477 switch(mode) {
02478 case 0:
02479
02480 switch(*e) {
02481 case '\"':
02482 mode = 1;
02483 break;
02484 case '\'':
02485 mode = 2;
02486 break;
02487 case '|':
02488 *value='\0';
02489 return e+1;
02490 }
02491 break;
02492 case 1:
02493 switch(*e) {
02494 case '\\':
02495 mode = 3;
02496 break;
02497 case '\"':
02498 mode = 0;
02499 }
02500 break;
02501 case 2:
02502 switch(*e) {
02503 case '\\':
02504 mode = 4;
02505 break;
02506 case '\'':
02507 mode = 0;
02508 }
02509 break;
02510 case 3:
02511 case 4:
02512 mode -= 2;
02513 }
02514 e++; value ++;
02515 }
02516 *value=0;
02517 return e;
02518
02519
02520 }
02521
02522 void nextActionArgumentStringBackwardCompatible(Pointer *e, Token *token) {
02523 skipWhitespace(e);
02524 Label start;
02525 token->exprloc = getFPos(&start, e, NULL)->exprloc;
02526 int ch = lookAhead(e, 0);
02527 if (ch==-1) {
02528 token->type = TK_EOS;
02529 strcpy(token->text,"EOS");
02530 } else {
02531 ch = lookAhead(e, 0);
02532 if(ch == '\"') {
02533 nextStringBase(e, token->text, "\"", 1, '\\', token->vars);
02534 skipWhitespace(e);
02535 } else if( ch == '\'') {
02536 nextStringBase(e, token->text, "\'", 1, '\\', token->vars);
02537 skipWhitespace(e);
02538 } else {
02539 nextStringParsed(e, token->text, "(", ")", ",|)", 0, token->vars);
02540
02541 int l0;
02542 l0 = strlen(token->text);
02543 while(isspace(token->text[l0-1])) {
02544 l0--;
02545 }
02546 token->text[l0++]='\0';
02547 }
02548 token->type = TK_STRING;
02549 }
02550 }
02551
02552 PARSER_FUNC_BEGIN(TypingConstraints)
02553 Hashtable *temp = context->symtable;
02554 context->symtable = newHashTable2(10, context->region);
02555 TRY(exec)
02556 NT(_TypingConstraints);
02557 FINALLY(exec)
02558 context->symtable = temp;
02559 END_TRY(exec)
02560
02561 PARSER_FUNC_END(TypingConstraints)
02562 PARSER_FUNC_BEGIN(Type)
02563 Hashtable *temp = context->symtable;
02564 context->symtable = newHashTable2(10, context->region);
02565 TRY(exec)
02566 NT2(_Type, 0, 0);
02567 FINALLY(exec)
02568 context->symtable = temp;
02569 END_TRY(exec)
02570 PARSER_FUNC_END(Type)
02571
02572 PARSER_FUNC_BEGIN(FuncType)
02573 Hashtable *temp = context->symtable;
02574 context->symtable = newHashTable2(10, context->region);
02575 TRY(exec)
02576 NT(_FuncType);
02577 OR(exec)
02578 NT2(_Type, 0, 0);
02579 BUILD_NODE(T_TUPLE, TUPLE, &start, 0, 0);
02580 SWAP;
02581 BUILD_NODE(T_CONS, FUNC, &start, 2, 2);
02582 FINALLY(exec)
02583 context->symtable = temp;
02584 END_TRY(exec)
02585 PARSER_FUNC_END(FuncType)
02586
02587 PARSER_FUNC_BEGIN2(_Type, int prec, int lifted)
02588 int rulegen = 1;
02589 int arity = 0;
02590 Node *node = NULL;
02591 TRY(type)
02592 ABORT(prec == 1);
02593 TRY(typeEnd)
02594 TTEXT_LOOKAHEAD("->");
02595 OR(typeEnd)
02596 TTEXT_LOOKAHEAD("=>");
02597 OR(typeEnd)
02598 TTEXT_LOOKAHEAD(")");
02599 OR(typeEnd)
02600 TTEXT_LOOKAHEAD(">");
02601 OR(typeEnd)
02602 TTYPE_LOOKAHEAD(TK_EOS);
02603 END_TRY(typeEnd)
02604 OR(type)
02605 LOOP_BEGIN(type)
02606 int cont = 0;
02607 Label vpos = *FPOS;
02608 TRY(type)
02609 TTYPE(TK_BACKQUOTED);
02610 BUILD_NODE(T_IRODS, token->text, &vpos, 0, 0);
02611 OR(type)
02612 TRY(typeVar)
02613 TTYPE(TK_INT);
02614 OR(typeVar)
02615 TTYPE(TK_TEXT);
02616 ABORT(!isupper(token->text[0]));
02617 END_TRY(typeVar)
02618 char *vname = cpStringExt(token->text, context->region);
02619
02620 Node *tvar;
02621 if ((tvar = (ExprType *) lookupFromHashTable(context->symtable, vname)) == NULL) {
02622 TRY(typeVarBound)
02623
02624 NT(TypeSet);
02625 OR(typeVarBound)
02626 BUILD_NODE(T_VAR, vname, &vpos, 0, 0);
02627 END_TRY(typeVarBound)
02628 tvar = POP;
02629 T_VAR_ID(tvar) = newTVarId();
02630 insertIntoHashTable(context->symtable, vname, tvar);
02631 }
02632 CASCADE(tvar);
02633 OR(type)
02634 TTEXT("?");
02635 CASCADE(newSimpType(T_DYNAMIC, context->region));
02636 OR(type)
02637 TTEXT2("integer", "int");
02638 CASCADE(newSimpType(T_INT, context->region));
02639 OR(type)
02640 TTEXT("double");
02641 CASCADE(newSimpType(T_DOUBLE, context->region));
02642 OR(type)
02643 TTEXT("boolean");
02644 CASCADE(newSimpType(T_BOOL, context->region));
02645 OR(type)
02646 TTEXT("time");
02647 CASCADE(newSimpType(T_DATETIME, context->region));
02648 OR(type)
02649 TTEXT("string");
02650 CASCADE(newSimpType(T_STRING, context->region));
02651 OR(type)
02652 TTEXT("list");
02653 NT2(_Type, 1, 0);
02654 BUILD_NODE(T_CONS, LIST, &vpos, 1, 1);
02655 Node *node = POP;
02656 setVararg(node, OPTION_VARARG_ONCE);
02657 PUSH(node);
02658 OR(type)
02659 TTEXT("unit");
02660 BUILD_NODE(T_TUPLE, TUPLE, &vpos, 0, 0);
02661 OR(type)
02662 TTEXT("(");
02663 NT2(_Type, 0, 0);
02664 TTEXT(")");
02665 OR(type)
02666 TTEXT("<")
02667 NT2(_Type, 0, 1);
02668 TTEXT(">");
02669 OR(type)
02670 TTEXT("forall");
02671 TTYPE(TK_TEXT);
02672 ABORT(!isupper(token->text[0]));
02673 char *vname = cpStringExt(token->text, context->region);
02674 TRY(typeVarBound)
02675 TTEXT("in");
02676 NT(TypeSet);
02677 OR(typeVarBound)
02678 BUILD_NODE(T_VAR, vname, &vpos, 0, 0);
02679 END_TRY(typeVarBound)
02680 Node *tvar = POP;
02681 T_VAR_ID(tvar) = newTVarId();
02682 TTEXT(",");
02683 insertIntoHashTable(context->symtable, vname, tvar);
02684 cont = 1;
02685 OR(type)
02686 TTEXT("f");
02687
02688 NT2(_Type, 1, 0);
02689 TRY(ftype)
02690 TTEXT("=>");
02691 NT2(_Type, 1, 0);
02692 BUILD_NODE(T_FIXD, NULL, &start, 2, 2);
02693 OR(ftype)
02694 BUILD_NODE(T_FLEX, NULL, &start, 1, 1);
02695 END_TRY(ftype);
02696
02697 OR(type)
02698 TTEXT2("output","o");
02699 NT2(_Type, 1, 0);
02700 node = POP;
02701 setIOType(node, IO_TYPE_OUTPUT);
02702 PUSH(node);
02703 OR(type)
02704 TTEXT2("input","i");
02705 NT2(_Type, 1, 0);
02706 node = POP;
02707 setIOType(node, IO_TYPE_INPUT | (getIOType(node) & IO_TYPE_OUTPUT));
02708 PUSH(node);
02709 OR(type)
02710 TTEXT2("expression","e");
02711 NT2(_Type, 1, 0);
02712 node = POP;
02713 setIOType(node, IO_TYPE_EXPRESSION);
02714 PUSH(node);
02715 OR(type)
02716 TTEXT2("actions","a");
02717 NT2(_Type, 1, 0);
02718 node = POP;
02719 setIOType(node, IO_TYPE_ACTIONS);
02720 PUSH(node);
02721 OR(type)
02722 TTEXT2("dynamic", "d");
02723 NT2(_Type, 1, 0);
02724 node = POP;
02725 setIOType(node, IO_TYPE_DYNAMIC);
02726 PUSH(node);
02727 OR(type)
02728 TTEXT("type");
02729 CASCADE(newSimpType(T_TYPE, context->region));
02730
02731 OR(type)
02732 TTEXT("set");
02733 CASCADE(newSimpType(T_TYPE, context->region));
02734
02735 OR(type)
02736 TTYPE(TK_TEXT);
02737 char *cons = cpStringExt(token->text, context->region);
02738
02739 int n = 0;
02740 OPTIONAL_BEGIN(argList)
02741 TTEXT("(");
02742 LOOP_BEGIN(args)
02743 NT2(_Type, 1, 0);
02744 n++;
02745 TRY(delim)
02746 TTEXT(",");
02747 OR(delim)
02748 DONE(args);
02749 END_TRY(delim)
02750 LOOP_END(args)
02751 TTEXT(")")
02752 OPTIONAL_END(argList)
02753 BUILD_NODE(T_CONS, cons, &start, n, n);
02754 END_TRY(type)
02755 if(!cont) {
02756 arity ++;
02757 TRY(typeEnd)
02758 ABORT(prec!=1);
02759 DONE(type);
02760 OR(typeEnd)
02761 TTYPE_LOOKAHEAD(TK_EOS);
02762 DONE(type);
02763 OR(typeEnd)
02764 TTEXT("*");
02765 TTEXT("->");
02766 PUSHBACK;
02767 PUSHBACK;
02768 DONE(type);
02769 OR(typeEnd)
02770 TTEXT("*");
02771 OR(typeEnd);
02772 DONE(type);
02773 END_TRY(typeEnd)
02774 }
02775 LOOP_END(type)
02776 END_TRY(type)
02777 if(arity != 1 || lifted) {
02778 BUILD_NODE(T_TUPLE, TUPLE, &start, arity, arity);
02779 }
02780 PARSER_FUNC_END(_Type)
02781
02782 PARSER_FUNC_BEGIN(TypeSet)
02783 int rulegen = 1;
02784 TTEXT("{");
02785 int n = 0;
02786 int done2 = 0;
02787 while (!done2 && NO_SYNTAX_ERROR) {
02788 NT2(_Type, 1, 0);
02789 n++;
02790 OPTIONAL_BEGIN(typeVarBoundEnd)
02791 TTEXT("}");
02792 done2 = 1;
02793 OPTIONAL_END(typeVarBoundEnd)
02794 }
02795 if(done2) {
02796 BUILD_NODE(T_VAR, NULL, &start, n, n);
02797 } else {
02798 break;
02799 }
02800 PARSER_FUNC_END(TypeSet)
02801
02802 PARSER_FUNC_BEGIN(_TypingConstraints)
02803 int rulegen = 1;
02804 TTEXT("{");
02805 int n = 0;
02806 LOOP_BEGIN(tc)
02807 Label pos2 = *FPOS;
02808 NT2(_Type, 0, 0);
02809 TTEXT("<=");
02810 NT2(_Type, 0, 0);
02811 BUILD_NODE(TC_LT, "", &pos2, 0, 0); /* node for generating error messages */
02812 BUILD_NODE(TC_LT, "<=", &pos2, 3, 3);
02813 n++;
02814 TRY(tce)
02815 TTEXT(",");
02816 OR(tce)
02817 TTEXT("}");
02818 DONE(tc);
02819 END_TRY(tce)
02820 LOOP_END(tc)
02821 BUILD_NODE(TC_SET, "{}", &start, n, n);
02822 PARSER_FUNC_END(TypingConstraints)
02823
02824 PARSER_FUNC_BEGIN(_FuncType)
02825 int rulegen = 1;
02826 int vararg = 0;
02827 NT2(_Type, 0, 1);
02828 TRY(vararg)
02829 TTEXT("*");
02830 vararg = OPTION_VARARG_STAR;
02831 OR(vararg)
02832 TTEXT("+");
02833 vararg = OPTION_VARARG_PLUS;
02834 OR(vararg)
02835 TTEXT("?");
02836 vararg = OPTION_VARARG_OPTIONAL;
02837 OR(vararg)
02838 vararg = OPTION_VARARG_ONCE;
02839 END_TRY(vararg)
02840 TTEXT("->");
02841 NT2(_Type, 0, 0);
02842 BUILD_NODE(T_CONS, FUNC, &start, 2, 2);
02843 Node *node = POP;
02844 setVararg(node, vararg);
02845 PUSH(node);
02846 PARSER_FUNC_END(_FuncType)
02847
02848 int parseRuleSet(Pointer *e, RuleSet *ruleSet, Env *funcDescIndex, int *errloc, rError_t *errmsg, Region *r) {
02849 char errbuf[ERR_MSG_LEN];
02850 Token *token;
02851 ParserContext *pc = newParserContext(errmsg, r);
02852
02853 int ret = 1;
02854 /* parser variables */
02855 int backwardCompatible = 0; /* 0 auto 1 true -1 false */
02856
02857 while(ret == 1) {
02858 pc->nodeStackTop = 0;
02859 pc->stackTopStackTop = 0;
02860 token = nextTokenRuleGen(e, pc, 1);
02861 switch(token->type) {
02862 case N_ERROR:
02863 return -1;
02864 case TK_EOS:
02865 ret = 0;
02866 continue;
02867 case TK_MISC_OP:
02868 case TK_TEXT:
02869 if(token->text[0] == '#') {
02870 skipComments(e);
02871 continue;
02872 } else if(token->text[0] == '@') { /* directive */
02873 token = nextTokenRuleGen(e, pc, 1);
02874 if(strcmp(token->text, "backwardCompatible")==0) {
02875 token = nextTokenRuleGen(e, pc, 1);
02876 if(token->type == TK_TEXT) {
02877 if(strcmp(token->text, "true")==0) {
02878 backwardCompatible = 1;
02879 } else if(strcmp(token->text, "false")==0) {
02880 backwardCompatible = -1;
02881 } else if(strcmp(token->text, "auto")==0) {
02882 backwardCompatible = 0;
02883 } else {
02884 /* todo error handling */
02885 }
02886 } else {
02887 /* todo error handling */
02888 }
02889 } else if(strcmp(token->text, "include")==0) {
02890 token = nextTokenRuleGen(e, pc, 1);
02891 if(token->type == TK_TEXT || token->type == TK_STRING) {
02892 CASCASE_NON_ZERO(readRuleSetFromFile(token->text, ruleSet, funcDescIndex, errloc, errmsg, r));
02893 } else {
02894 /* todo error handling */
02895 }
02896 } else {
02897 /* todo error handling */
02898 }
02899 continue;
02900 }
02901 break;
02902 default:
02903 break;
02904 }
02905 pushback(e, token, pc);
02906
02907 Node *node = parseRuleRuleGen(e, backwardCompatible, pc);
02908 if(node==NULL) {
02909 addRErrorMsg(errmsg, RE_OUT_OF_MEMORY, "parseRuleSet: out of memory.");
02910 return RE_OUT_OF_MEMORY;
02911 } else if(getNodeType(node) == N_ERROR) {
02912 *errloc = NODE_EXPR_POS(node);
02913 generateErrMsg("parseRuleSet: error parsing rule.", *errloc, e->base, errbuf);
02914 addRErrorMsg(errmsg, RE_PARSER_ERROR, errbuf);
02915 /* skip the current line and try to parse the rule from the next line */
02916 skipComments(e);
02917 return RE_PARSER_ERROR;
02918 } else {
02919 int n = node->degree;
02920 Node **nodes = node->subtrees;
02921 RuleType rk;
02922 /* if(strcmp(node->text, "UNPARSED") == 0) {
02923 pushRule(ruleSet, newRuleDesc(RK_UNPARSED, nodes[0], r));
02924 } else */ if(strcmp(node->text, "INDUCT") == 0) {
02925 int k;
02926 pushRule(ruleSet, newRuleDesc(RK_DATA, nodes[0], 0, r));
02927 for(k=1;k<n;k++) {
02928 if(lookupFromEnv(funcDescIndex, nodes[k]->subtrees[0]->text)!=NULL) {
02929 generateErrMsg("parseRuleSet: redefinition of constructor.", NODE_EXPR_POS(nodes[k]->subtrees[0]), nodes[k]->subtrees[0]->base, errbuf);
02930 addRErrorMsg(errmsg, RE_TYPE_ERROR, errbuf);
02931 return RE_TYPE_ERROR;
02932 }
02933 insertIntoHashTable(funcDescIndex->current, nodes[k]->subtrees[0]->text, newConstructorFD2(nodes[k]->subtrees[1], r));
02934 pushRule(ruleSet, newRuleDesc(RK_CONSTRUCTOR, nodes[k], 0, r));
02935 }
02936 } else if(strcmp(node->text, "CONSTR") == 0) {
02937 if(lookupFromEnv(funcDescIndex, nodes[0]->subtrees[0]->text)!=NULL) {
02938 generateErrMsg("parseRuleSet: redefinition of constructor.", NODE_EXPR_POS(nodes[0]->subtrees[0]), nodes[0]->subtrees[0]->base, errbuf);
02939 addRErrorMsg(errmsg, RE_TYPE_ERROR, errbuf);
02940 return RE_TYPE_ERROR;
02941 }
02942 insertIntoHashTable(funcDescIndex->current, nodes[0]->subtrees[0]->text, newConstructorFD2(nodes[0]->subtrees[1], r));
02943 pushRule(ruleSet, newRuleDesc(RK_CONSTRUCTOR, nodes[0], 0, r));
02944 } else if(strcmp(node->text, "EXTERN") == 0) {
02945 FunctionDesc *fd;
02946 if((fd = (FunctionDesc *) lookupFromEnv(funcDescIndex, nodes[0]->subtrees[0]->text))!=NULL) {
02947 generateErrMsg("parseRuleSet: redefinition of function.", NODE_EXPR_POS(nodes[0]->subtrees[0]), nodes[0]->subtrees[0]->base, errbuf);
02948 addRErrorMsg(errmsg, RE_TYPE_ERROR, errbuf);
02949 return RE_TYPE_ERROR;
02950 }
02951 insertIntoHashTable(funcDescIndex->current, nodes[0]->subtrees[0]->text, newExternalFD(nodes[0]->subtrees[1], r));
02952 pushRule(ruleSet, newRuleDesc(RK_EXTERN, nodes[0], 0, r));
02953 } else {
02954 int notyping;
02955 if(strcmp(node->text, "REL")==0) {
02956 rk = RK_REL;
02957 notyping = backwardCompatible >= 0 ? 1 : 0;
02958 } else if(strcmp(node->text, "FUNC")==0) {
02959 rk = RK_FUNC;
02960 notyping = 0;
02961 }
02962 int k;
02963 for(k=0;k<n;k++) {
02964 Node *node = nodes[k];
02965 pushRule(ruleSet, newRuleDesc(rk, node, notyping, r));
02966 /* printf("%s\n", node->subtrees[0]->text);
02967 printTree(node, 0); */
02968 }
02969 }
02970 }
02971 }
02972 deleteParserContext(pc);
02973 return 0;
02974 }
02975
02976 /*
02977 * parse the string for an ExprType
02978 * supported types:
02979 * ? dynamic
02980 * i integer
02981 * b boolean
02982 * d double
02983 * t time
02984 * s string
02985 * list <type> list
02986 * f <type> flexible
02987 * <var> ({ <type> ... <type> })? variable
02988 * <type> * ... * <type> product
02989 * < <type> * ... * <type> > lifted product
02990 * `irods PI` irods
02991 *
02992 * <type> (*|+|?)? -> <type> function
02993 * forall <var> (in { <type> ... <type> })?, <type> universal
02994 */
02995 Node* parseFuncTypeFromString(char *string, Region *r) {
02996 Pointer *p = newPointer2(string);
02997 ParserContext *pc = newParserContext(NULL, r);
02998 nextRuleGenFuncType(p, pc);
02999 Node *exprType = pc->nodeStack[0];
03000 deleteParserContext(pc);
03001 deletePointer(p);
03002 return exprType;
03003 }
03004 Node* parseTypingConstraintsFromString(char *string, Region *r) {
03005 Pointer *p = newPointer2(string);
03006 ParserContext *pc = newParserContext(NULL, r);
03007 nextRuleGenTypingConstraints(p, pc);
03008 Node *exprType = pc->nodeStack[0];
03009 /*char buf[ERR_MSG_LEN];
03010 errMsgToString(pc->errmsg, buf, ERR_MSG_LEN);
03011 printf("%s", buf);*/
03012 deleteParserContext(pc);
03013 deletePointer(p);
03014 return exprType;
03015 }
03016 Node *parseRuleRuleGen(Pointer *expr, int backwardCompatible, ParserContext *pc) {
03017 nextRuleGenRule(expr, pc, backwardCompatible);
03018 Node *rulePackNode = pc->nodeStack[0];
03019 if(pc->error) {
03020 if(pc->errnode!=NULL) {
03021 rulePackNode =pc->errnode;
03022 } else {
03023 rulePackNode =createErrorNode("parser error", &pc->errloc, pc->region);
03024 }
03025 }
03026 return rulePackNode;
03027 }
03028 Node *parseTermRuleGen(Pointer *expr, int rulegen, ParserContext *pc) {
03029 nextRuleGenTerm(expr, pc, rulegen, 0);
03030 Node *rulePackNode = pc->nodeStack[0];
03031 if(pc->error) {
03032 if(pc->errnode!=NULL) {
03033 rulePackNode =pc->errnode;
03034 } else {
03035 rulePackNode =createErrorNode("parser error", &pc->errloc, pc->region);
03036 }
03037 }
03038
03039 return rulePackNode;
03040
03041 }
03042 Node *parseActionsRuleGen(Pointer *expr, int rulegen, int backwardCompatible, ParserContext *pc) {
03043 nextRuleGenActions(expr, pc, rulegen, backwardCompatible);
03044 Node *rulePackNode = pc->nodeStack[0];
03045 if(pc->error) {
03046 if(pc->errnode!=NULL) {
03047 rulePackNode =pc->errnode;
03048 } else {
03049 rulePackNode =createErrorNode("parser error", &pc->errloc, pc->region);
03050 }
03051 }
03052
03053 return rulePackNode;
03054
03055 }
03056 char* typeName_Res(Res *s) {
03057 return typeName_ExprType(s->exprType);
03058 }
03059
03060 char* typeName_ExprType(ExprType *s) {
03061 switch(getNodeType(s)) {
03062 case T_IRODS:
03063 return s->text;
03064 default:
03065 return typeName_NodeType(getNodeType(s));
03066 }
03067 }
03068
03069 char* typeName_Parser(NodeType s) {
03070 switch(s) {
03071 case T_IRODS:
03072 return "IRODS";
03073 case T_VAR:
03074 return "VAR";
03075 case T_DYNAMIC:
03076 return "?";
03077 case T_CONS:
03078 return "CONS";
03079 case T_FLEX:
03080 return "f";
03081 case T_FIXD:
03082 return "f";
03083 case T_BOOL:
03084 return "boolean";
03085 case T_INT:
03086 return "integer";
03087 case T_DOUBLE:
03088 return "double";
03089 case T_STRING:
03090 return "string";
03091 case T_ERROR:
03092 return "ERROR";
03093 case T_DATETIME:
03094 return "time";
03095 case T_TYPE:
03096 return "set";
03097 case T_TUPLE:
03098 return "TUPLE";
03099 default:
03100 return "OTHER";
03101 }
03102 }
03103
03104 char* typeName_NodeType(NodeType s) {
03105 switch(s) {
03106 case T_IRODS:
03107 return "IRODS";
03108 case T_VAR:
03109 return "VAR";
03110 case T_DYNAMIC:
03111 return "DYNAMIC";
03112 case T_CONS:
03113 return "CONS";
03114 case T_FLEX:
03115 return "FLEX";
03116 case T_FIXD:
03117 return "FIXD";
03118 case T_BOOL:
03119 return "BOOLEAN";
03120 case T_INT:
03121 return "INTEGER";
03122 case T_DOUBLE:
03123 return "DOUBLE";
03124 case T_STRING:
03125 return "STRING";
03126 case T_ERROR:
03127 return "ERROR";
03128 case T_DATETIME:
03129 return "DATETIME";
03130 case T_TYPE:
03131 return "TYPE";
03132 case T_TUPLE:
03133 return "TUPLE";
03134 default:
03135 return "OTHER";
03136 }
03137 }
03138
03139 void generateErrMsgFromFile(char *msg, long errloc, char *ruleBaseName, char* ruleBasePath, char errbuf[ERR_MSG_LEN]) {
03140 FILE *fp = fopen(ruleBasePath, "r");
03141 Pointer *e = newPointer(fp, ruleBaseName);
03142 Label l;
03143 l.base = NULL;
03144 l.exprloc = errloc;
03145 generateErrMsgFromPointer(msg, &l, e, errbuf);
03146 deletePointer(e);
03147 }
03148
03149 void generateErrMsgFromSource(char *msg, long errloc, char *src, char errbuf[ERR_MSG_LEN]) {
03150 Pointer *e = newPointer2(src);
03151 Label l;
03152 l.base = NULL;
03153 l.exprloc = errloc;
03154 generateErrMsgFromPointer(msg, &l, e, errbuf);
03155 deletePointer(e);
03156 }
03157 void generateErrMsgFromPointer(char *msg, Label *l, Pointer *e, char errbuf[ERR_MSG_LEN]) {
03158 char buf[ERR_MSG_LEN];
03159 dupLine(e, l, ERR_MSG_LEN, buf);
03160 int len = strlen(buf);
03161 int coor[2];
03162 getCoor(e, l, coor);
03163 int i;
03164 if(len < ERR_MSG_LEN - 1) {
03165 buf[len++] = '\n';
03166 }
03167 for(i=0;i<coor[1];i++) {
03168 if(len >= ERR_MSG_LEN - 1) {
03169 break;
03170 }
03171 buf[len++] = buf[i] == '\t'?'\t':' ';
03172 }
03173 if(len < ERR_MSG_LEN - 2) {
03174 buf[len++] = '^';
03175 }
03176 buf[len++] = '\0';
03177 if(e->isFile)
03178 snprintf(errbuf, ERR_MSG_LEN,
03179 "%s\nline %d, col %d, rule base %s\n%s\n", msg, coor[0], coor[1], e->base+1, buf);
03180 else
03181 snprintf(errbuf, ERR_MSG_LEN,
03182 "%s\nline %d, col %d\n%s\n", msg, coor[0], coor[1], buf);
03183
03184 }
03185 void generateAndAddErrMsg(char *msg, Node *node, int errcode, rError_t *errmsg) {
03186 char errmsgBuf[ERR_MSG_LEN];
03187 generateErrMsg(msg, NODE_EXPR_POS(node), node->base, errmsgBuf);
03188 addRErrorMsg(errmsg, errcode, errmsgBuf);
03189 }
03190 char *generateErrMsg(char *msg, long errloc, char *ruleBaseName, char errmsg[ERR_MSG_LEN]) {
03191 char ruleBasePath[MAX_NAME_LEN];
03192 switch(ruleBaseName[0]) {
03193 case 's': // source
03194 generateErrMsgFromSource(msg, errloc, ruleBaseName + 1, errmsg);
03195 return errmsg;
03196 case 'f': // file
03197 getRuleBasePath(ruleBaseName + 1, ruleBasePath);
03198 generateErrMsgFromFile(msg, errloc, ruleBaseName + 1, ruleBasePath, errmsg);
03199 return errmsg;
03200 default:
03201 snprintf(errmsg, ERR_MSG_LEN, "<unknown source type>");
03202 return errmsg;
03203 }
03204 }