void factor() /* 式の因子のコンパイル */ { int tIndex, i; KeyId k; if (token.kind==Id){ tIndex = searchT(token.u.id, varId); setIdKind(k=kindT(tIndex)); /* 印字のための情報のセット */ switch (k) { case varId: case parId: /* 変数名かパラメタ名 */ genCodeT(lod, tIndex); token = nextToken(); break; case constId: /* 定数名 */ genCodeV(lit, val(tIndex)); token = nextToken(); break; case funcId: /* 関数呼び出し */ token = nextToken(); if (token.kind==Lparen){ i=0; /* iは実引数の個数 */ token = nextToken(); if (token.kind != Rparen) { for (; ; ) { expression(); i++; /* 実引数のコンパイル */ if (token.kind==Comma){ /* 次がコンマなら実引数が続く */ token = nextToken(); continue; } token = checkGet(token, Rparen); break; } } else token = nextToken(); if (pars(tIndex) != i) errorMessage("\\#par"); /* pars(tIndex)は仮引数の個数 */ }else{ errorInsert(Lparen); errorInsert(Rparen); } genCodeT(cal, tIndex); /* call命令 */ break; } }else if (token.kind==Num){ /* 定数 */ genCodeV(lit, token.u.value); token = nextToken(); }else if (token.kind==Lparen){ /* 「(」「因子」「)」 */ token = nextToken(); expression(); token = checkGet(token, Rparen); } switch (token.kind){ /* 因子の後がまた因子ならエラー */ case Id: case Num: case Lparen: errorMissingOp(); factor(); default: return; } }
// encodes the input stream by taking advantage of lzw algorithm // also implements logic to prune the trie structure used to store the string // table, and escapes single character codes void encode(int e, int m, int p) { Trie st; createT(&st, e); int c = EMPTY; // same as (EMPTY, K), index of the prefix // int value of char k we are testing to see if c,k exists in the table int k; // number of codes you have inserted, 256 without escape flag... int codeCount = (e) ? 3 : 259; int bitCount = (e) ? 2 : 9; int maxbits = (m<=8 || m>20) ? 12 : m; int maxcodes = (1 << maxbits); int firstRead = false; // if first read of k when e flag is present int pruneCount = 0; printf("%02d:%d:%d:", maxbits, p, e); while((k = getchar())!= EOF) { st[c].appearances++; int ck = searchT(&st, c, k, e); // will increment c's appearance once // if ck is not in the table if(ck<0) { // if prune flag & reached maxcodes, do a prune before next insert // into the table, putBits 0 to indicate a prune has occurred // a prune should likewise happen in decode if(c!=EMPTY) { putBits(bitCount, c); } // add ck to the table as long as (e && c == EMPTY) is false // we will add (empty, k) to the table after this condition // !e and c==EMPTY will never happen, bc all chars will have been // added as children to empty // prune right before we reach maxcodes, we would have lost the next // code we insert anyways, now we won't lose k if(p&&(codeCount+1==maxcodes)) { putBits(bitCount, 0); pruneCount++; Trie newst; createT(&newst, e); int oldCodeCount = codeCount; codeCount=pruneT(&st, &newst, e, oldCodeCount); destroyT(&st, oldCodeCount); st = newst; bitCount=codeLength(codeCount); c=EMPTY; ungetc(k, stdin); continue; } // if(!e || c!=EMPTY) { if(codeCount<maxcodes) { if(tableFilled(codeCount+1)) { int newSize = (codeCount+1)*2; expandT(&st, newSize); bitCount++; } addT(&st, c, k, codeCount); codeCount++; } } // if escape flag is on and k is not yet added to the table if(e && searchT(&st, EMPTY, k, e) < 0) { putBits(bitCount, ESC); // 1 is the index of escape character putBits(8, k); if(codeCount<maxcodes) { if(codeLength(codeCount+1)-codeLength(codeCount)) { int newSize = (codeCount+1)*2; expandT(&st, newSize); bitCount++; } addT(&st, EMPTY, k, codeCount); codeCount++; } firstRead=true; // encode escaped something, don't unget(k) // if this happens } c = EMPTY; // make c empty again if(!firstRead) { ungetc(k, stdin); // put k back to start reading } // a new character else { firstRead = false; } } else { c=ck; // set c to index of next code } } if(c!=EMPTY) { putBits(bitCount, c); } putBits(bitCount, EOFILE); // puts EOF flushBits(); destroyT(&st, codeCount); }
void statement() /* 文のコンパイル */ { int tIndex; KindT k; int backP, backP2; /* バックパッチ用 */ while(1) { switch (token.kind) { case Id: /* 代入文のコンパイル */ tIndex = searchT(token.u.id, varId); /* 左辺の変数のインデックス */ setIdKind(k=kindT(tIndex)); /* 印字のための情報のセット */ if (k != varId && k != parId) /* 変数名かパラメタ名のはず */ errorType("var/par"); token = checkGet(nextToken(), Assign); /* ":="のはず */ expression(); /* 式のコンパイル */ genCodeT(sto, tIndex); /* 左辺への代入命令 */ return; case If: /* if文のコンパイル */ token = nextToken(); condition(); /* 条件式のコンパイル */ token = checkGet(token, Then); /* "then"のはず */ backP = genCodeV(jpc, 0); /* jpc命令 */ statement(); /* 文のコンパイル */ backPatch(backP); /* 上のjpc命令にバックパッチ */ return; case Ret: /* return文のコンパイル */ token = nextToken(); expression(); /* 式のコンパイル */ genCodeR(); /* ret命令 */ return; case Begin: /* begin . . end文のコンパイル */ token = nextToken(); while(1){ statement(); /* 文のコンパイル */ while(1){ if (token.kind==Semicolon){ /* 次が";"なら文が続く */ token = nextToken(); break; } if (token.kind==End){ /* 次がendなら終り */ token = nextToken(); return; } if (isStBeginKey(token)){ /* 次が文の先頭記号なら */ errorInsert(Semicolon); /* ";"を忘れたことにする */ break; } errorDelete(); /* それ以外ならエラーとして読み捨てる */ token = nextToken(); } } case While: /* while文のコンパイル */ token = nextToken(); backP2 = nextCode(); /* while文の最後のjmp命令の飛び先 */ condition(); /* 条件式のコンパイル */ token = checkGet(token, Do); /* "do"のはず */ backP = genCodeV(jpc, 0); /* 条件式が偽のとき飛び出すjpc命令 */ statement(); /* 文のコンパイル */ genCodeV(jmp, backP2); /* while文の先頭へのジャンプ命令 */ backPatch(backP); /* 偽のとき飛び出すjpc命令へのバックパッチ */ return; case Write: /* write文のコンパイル */ token = nextToken(); expression(); /* 式のコンパイル */ genCodeO(wrt); /* その値を出力するwrt命令 */ return; case WriteLn: /* writeln文のコンパイル */ token = nextToken(); genCodeO(wrl); /* 改行を出力するwrl命令 */ return; case End: case Semicolon: /* 空文を読んだことにして終り */ return; default: /* 文の先頭のキーまで読み捨てる */ errorDelete(); /* 今読んだトークンを読み捨てる */ token = nextToken(); continue; } } }
/* RubikSq.c | Stephen Krewson | CPSC 223b. USAGE: RubikSq [-r] [HEIGHT WIDTH] MAXLENGTH INITIAL GOAL. RubikSq solves a Rubik's square puzzle using a trie data structure and breadth-first search to find the fewest number of moves necessary to transform INITIAL into GOAL. */ int main (int argc, char *argv[]) { // 1. PARSING COMMAND-LINE ARGS bool rFlag = false; int maxLength = 0; int pos = 0; // pos is counter for moving through argv[] int height = 3, width = 3; // default values char *initial = NULL; char *goal = NULL; if (argc % 2 != 0) // "-r" specified { if (argc > 3) { if (strcmp(argv[1], "-r") != 0) KILL("ERROR: '-r' flag improperly specified."); else rFlag = true; } else KILL("ERROR: Insufficient number of arguments."); } if (argc == 6 || argc == 7) // HEIGHT and WIDTH specified { // Indexes depend on -r flag pos = (rFlag == true) ? 2 : 1; initial = strdup(argv[pos+3]); // use malloc bc we will call free() goal = strdup(argv[pos+4]); // on all the dict nodes if (!(height = atoi(argv[pos])) || !(width = atoi(argv[pos+1])) || (height < 2 || height > 5) || (width < 2 || width > 5)) KILL("ERROR: Invalid HEIGHT and WIDTH values."); char *endPtr; maxLength = (int) strtol(argv[pos+2], &endPtr, 10); if (endPtr < argv[pos+2] + strlen(argv[pos+2])) KILL("ERROR: MAXLENGTH contains nun-numeric characters."); else if (maxLength < 0) KILL ("ERROR: MAXLENGTH is negative."); if (!checkTray(height, width, initial, goal)) KILL("ERROR: Invalid tray sequences."); } // HEIGHT, WIDTH NOT specified else if (argc == 4 || argc == 5) { pos = (rFlag == true) ? 2 : 1; initial = strdup(argv[pos+1]); goal = strdup(argv[pos+2]); char *endPtr; maxLength = (int) strtol(argv[pos], &endPtr, 10); if (endPtr < argv[pos] + strlen(argv[pos])) KILL("ERROR: MAXLENGTH contains nun-numeric characters."); else if (maxLength < 0) KILL ("ERROR: MAXLENGTH is negative."); if (!checkTray(height, width, initial, goal)) KILL("ERROR: Invalid tray sequences."); } else { KILL("ERROR: Invalid number of arguments."); } Trie dict; // Initialize trie data structure createT(&dict); Stack stk1, stk2; // Initialize the "queue" createS(&stk1); createS(&stk2); char *currentPos = NULL; // pointer for position being processed char *prevPos = NULL; // pointer to "from" attr in the dict long lengthPos = 0; // address to hold "length" attr in the dict int permutations = 0; // hold # of permutations getPerms returns insertT(&dict, goal, NULL, 0); // Add GOAL to dictionary enqueue(&stk1, &stk2, goal); // push GOAL onto the queue while (!isEmptyQ(&stk1, &stk2)) // While the queue is not empty { dequeue(&stk1, &stk2, ¤tPos); // Remove P from head of queue searchT(&dict, currentPos, &prevPos, &lengthPos); // lengPos holds length of P if (lengthPos + 2 < maxLength) // +2 because currentPos is 1 { // more than the previous distance and each // permutation is another distance of 1 char **perms; // array of pointers to permutations of P perms = getPerms(currentPos, height, width, rFlag, &permutations); for (int j = 0; j < permutations; j++) // for each position . . . { if (strcmp(initial, perms[j]) == 0) // if P' is the INITIAL { // add it so we can trace insertT(&dict, perms[j], currentPos, lengthPos+1); printf("%s\n", initial); // print INITIAL printf("%s\n", currentPos); // reached INITIAL from... char *holder2; // follow path of search holder2 = currentPos; // start at currentPos while (strcmp(holder2, goal) != 0) { if(!searchT(&dict, currentPos, &holder2, &lengthPos)) { KILL("ERROR: searchT() failed."); } printf("%s\n", holder2); currentPos = holder2; } destroyS(&stk1); // get rid of the queue destroyS(&stk2); deleteT(dict, dict); free(dict); // Remember root node free(perms[j]); free(perms); // free the pointer array exit(0); // Successful exit! } else if (!searchT(&dict, perms[j], &prevPos, &lengthPos)) { // Put p' in dict, on queue if (!insertT(&dict, perms[j], currentPos, lengthPos+1)) { KILL("ERROR: insertT() failed."); } enqueue(&stk1, &stk2, perms[j]); } else // else P' is already in the dictionary { free(perms[j]); // don't need it anymore! } } free(perms); // Free the pointer array } } destroyS(&stk1); // Cleanup in case of no valid sequence destroyS(&stk2); deleteT(dict, dict); free(dict); // Remember to clean root node of dict return EXIT_SUCCESS; }