// 比較演算 static void genCmpExpr(int node, struct Expr* c) { int lval = syGetLVal(node); // 左辺 int rval = syGetRVal(node); // 右辺 boolean swap = false; if (evalDepth(lval) < evalDepth(rval)) { // 右辺が左辺より int tmp = lval; // 多くスタックを使うなら lval = rval; // 左右の辺を入れ換える rval = tmp; swap = true; } // 両辺を処理する genExpr(lval, c); // 左辺を評価し値をロード genExpr(rval, c); // 右辺を評価し値をロード int typ = syGetType(node); // 演算の種類により命令を出力 if (swap) { // 左右の辺が交換済みなら if (typ==SyGT) vmLt(); // GT( > ) は LT( < ) else if (typ==SyGE) vmLe(); // GE( >= ) は LE( <= ) else if (typ==SyLT) vmGt(); // LT( < ) は GT( > ) else if (typ==SyLE) vmGe(); // LE( <= ) は GE( >= ) else if (typ==SyEQU) vmEq(); // EQ( == ) はそのまま else if (typ==SyNEQ) vmNe(); // NE( != ) はそのまま else error("バグ...genCmpExpr(1)"); } else { if (typ==SyGT) vmGt(); // GT ( > ) else if (typ==SyGE) vmGe(); // GE ( >= ) else if (typ==SyLT) vmLt(); // LT ( < ) else if (typ==SyLE) vmLe(); // LE ( <= ) else if (typ==SyEQU) vmEq(); // EQ ( == ) else if (typ==SyNEQ) vmNe(); // NE ( != ) else error("バグ...genCmpExpr(2)"); } }
// 二項演算の基本形 (数値演算に使用) static void gen2OpExpr(int node, struct Expr* c) { int typ = syGetType(node); // 演算の種類 int lval = syGetLVal(node); // 左辺 int rval = syGetRVal(node); // 右辺 boolean swap = false; if (isCommutativeOp(typ) && // 左右を可換な演算で右辺が evalDepth(lval) < evalDepth(rval)) { // 多くのスタックを使うなら int tmp = lval; // 左右の辺を入れ換える lval = rval; rval = tmp; swap = true; } // 両辺を処理する genExpr(lval, c); // 左辺を評価し値をロード genExpr(rval, c); // 右辺を評価し値をロード if (typ==SyADD) vmAdd(); // ADD (足し算) else if (typ==SySUB) vmSub(); // SUB (引き算) else if (typ==SySHL) vmShl(); // SHL (左シフト) else if (typ==SySHR) vmShr(); // SHR (右シフト) else if (typ==SyBAND) vmBAnd(); // BAND (ビット毎AND) else if (typ==SyBXOR) vmBXor(); // BXOR (ビット毎XOR) else if (typ==SyBOR) vmBOr(); // BOR (ビット毎OR) else if (typ==SyMUL) vmMul(); // MUL (掛け算) else if (typ==SyDIV) vmDiv(); // DIV (割り算) else if (typ==SyMOD) vmMod(); // MOD (余り) else error("バグ...gen2OpExpr"); }
// 後置演算(配列アクセス) static void genIdxExpr(int node, struct Expr* c, int place) { int lval = syGetLVal(node); // 左辺 int rval = syGetRVal(node); // 右辺 genExpr(lval, c); // 左辺を評価し値をロード genExpr(rval, c); // 右辺を評価し値をロード c->place=place; // ワード配列/バイト配列 }
// 単項演算 static void gen1OpExpr(int node, struct Expr* c) { genExpr(syGetLVal(node), c); // 式を評価しスタックに積む int typ = syGetType(node); // 演算の種類により命令を出力 if (typ == SyNEG) vmNeg(); // NEG (2の補数) else if (typ == SyNOT) vmNot(); // NOT (論理の否定) else if (typ == SyBNOT) vmBNot(); // BNOT (1の補数) else if (typ == SyCHR) vmChr(); // CHR (文字型への変換) else if (typ == SyBOOL) vmBool(); // BOOL (論理型への変換) else error("バグ...gen1OpExpr"); }
// return 文 static void genRet(int node) { if (syGetLVal(node)!=SyNULL) { // 返す値があれば struct Expr *c = newExpr(); // Expr を割り当て genExpr(syGetLVal(node), c); // 返す式を処理し値をロード vmMReg(); // ハードウェアレジスタに free(c); // 移動する } int root = syGetRoot(); if (root!=node && syGetRVal(root)!=node) { // 関数の最後の文でないなら if (retLab==-1) retLab = newLab(); // ラベルを割り当て vmJmp(retLab); // そこにジャンプする } }
// 後置演算(構造体アクセス) static void genDotExpr(int node, struct Expr* c) { int lval = syGetLVal(node); // 構造体アドレス int rval = syGetRVal(node); // 定数ノードに名前表の int idx = syGetLVal(rval); // インデクスが入っている genExpr(lval, c); // 左辺を評価し値をロード // 2項演算に分類しているので式の体裁を整える c->place = CNST; // 定数値として c->value = ntGetCnt(idx); // フィールドオフセットを load(c); // ロードする c->place = STKW; // ワード配列と同様な扱い }
// 論理演算子(&& と ||)の処理 static int genLogExpr(int node, struct Expr *c, int left, struct Label *lab1, struct Label *lab2) { int curOp = syGetType(node); // 現在の演算子 // 左辺を処理する int lNode = syGetLVal(node); // 左に進む場合のノード int lOp = syGetType(lNode); // 左の演算子 if (lOp==SyOR || lOp==SyAND) { // 左に論理式が続く場合 struct Label *labN = newLabel(left+1); // 新しいラベルを準備 if (lOp == curOp) // 同じ演算子なら genLogExpr(lNode, c, left+1, lab1, labN); // このように ^^;;; else // そうでなければ genLogExpr(lNode, c, left+1, labN, lab1); // このように ^^;;; printLab(labN->no); // no が -1 以外なら印刷 free(labN); } else { // 左辺が論理式以外の場合 genExpr(lNode, c); // 論理値を求め boolJmp(curOp==SyOR, c, lab1); // 条件ジャンプ命令を生成 } // 右辺を処理する int rNode = syGetRVal(node); // 右に進む場合のノード int rrNode = rNode; // 最後(最も右)の項 int rOp = syGetType(rNode); // 右の演算子 if (rOp==SyOR || rOp==SyAND) { // 右に論理式が続く場合 if (rOp == curOp) // 同じ演算子なら rrNode=genLogExpr(rNode,c,left,lab1,lab2); // このように ^^;;; else // そうでなければ rrNode=genLogExpr(rNode,c,left,lab2,lab1); // このように ^^;;; } else if (left>=2) { // 式の最後の項以外なら genExpr(rNode, c); // 論理値を求め if (lab1->left == left) // lab1 の直前の項なら boolJmp(curOp!=SyOR, c, lab2); // 逆の条件で lab2 へ飛ぶ else boolJmp(curOp==SyOR, c, lab1); // 条件ジャンプ命令を生成 } // else { } // 式の最後の項は特別なので呼び出し側で処理する return rrNode; }
// genLogExpr を使用して論理値を求める static void genLOpExpr(int node, struct Expr* c) { int op = syGetType(node); // 論理和か論理積か int lab0 = newLab(); // 論理式の最後 struct Label *lab1 = newLabel(0); // 途中で結果が出たとき struct Label *lab2 = newLabel(1); // 途中で結果が出たとき int rNode = genLogExpr(node, c, 1, lab2, lab1); // コード生成 genExpr(rNode, c); // 最後の項の論理値を求める if (op==SyOR) // || なら vmBoolOR(lab2->no, lab1->no, lab0); // BOOLOR マクロ命令を生成 else // && なら vmBoolAND(lab2->no, lab1->no, lab0); // BOOLAND マクロ命令を生成 free(lab1); free(lab2); }
/// 関数の実引数をスタックに積む static int genArgs(int node, struct Expr* c) { int n = 0; // 引数の個数を数えるカウンタ while (node!=SyNULL) { // 引数がある間 int typ = syGetType(node); int exp; if (typ == SySEMI) { // リストなら exp = syGetRVal(node); // 右側に式 node = syGetLVal(node); // 次は左に進む } else { // リスト以外(式)なら exp = node; // 自身が式 node = SyNULL; // 次は無い } genExpr(exp, c); // 引数を評価しスタックに積む vmArg(); // 引数値を引数領域に移動 n = n + 1; // 引数の個数をカウント } return n; // 引数の個数を返す }
/* Generate code for expressions appearing as actual parameters. * Recursive method pushes actuals in reverse order. */ void genActuals(node *actualList, decldesc *formal) { // use recursive strategy: // if the lists are NULL, we're done // otherwise, call genActuals recursively with the rests of // both lists (which will generate code to push the parameters // in reverse order) // then, generate code to compute the current actual // - it it's an array parameter, need to adjust the displacement again // since the called function thinks the lowbound is 0 // - if it's a refparam (which includes arrays), call computeAddress // finally, push the actual on the stack if (!actualList) return; node *actual = actualList->internal.child[0]; node *nextActualList = actualList->internal.child[1]; decldesc *formalList = formal->formal.formallink; int line = actual->unk.line; int typesize; typedesc* type0; if (actualList->internal.child[1] != NULL ) { genActuals(nextActualList, formalList); } opdesc *op0 = genExpr(actual); //if it's an array if (actual->unk.type == Nident && actual->ident.decl->var.vartype->isArray == TRUE) { type0 = actual->ident.decl->var.vartype; typesize = type0->typespec == integer ? INTSIZE : BOOLSIZE; // adjust the base address if lowbound != 0 op0->disp -= typesize * type0->lowbound; } if(formal->formal.valparam == FALSE) //if it's a ref param op0 = computeAddress(op0, line); //push onto the stack outputCmd("pushl", line); outputOp(op0); freeOp(op0); }
/* generate code for a return statement */ void genReturn(node *stmt, codelabel *next) { if(stmt->internal.child[0]) { opdesc *op = genExpr(stmt->internal.child[0]); op = forceToSpecificReg(op, eax, stmt->unk.line); freeOp(op); } if (next != &funend) { outputCmd("jmp", stmt->internal.line); outputLabel(&funend); } else { outputCmd(NULL, stmt->internal.line); /* do nothing -- fall through */ } // Note that you don't need to output a "jmp" // statement if next is the same as &funend }
/* generate code for an assignment statement */ void genAssign(node *stmt) { node *var = stmt->internal.child[0]; node *expr = stmt->internal.child[1]; assert (stmt->unk.type == Nassign || stmt->unk.type == Ndecl); if (expr == NULL) return; /* declaration without assignment */ opdesc *value = genExpr(expr); opdesc *target = genVar(var); if (isMemloc(value)) value = forceToReg(value, stmt->internal.line); outputCmd("movl", stmt->internal.line); outputOp(value); outputOp(target); freeOp(value); freeOp(target); }
// 条件式の生成(条件式(node)を評価し true/false なら lab へジャンプする) static void genCnd(int node, boolean tf, struct Label *jmpLab) { struct Expr *c = newExpr(); // Expr を割り当てる struct Label *nxtLab = newLabel(2); // 式の直後用ラベル int op = syGetType(node); if (op==SyOR) { // 条件式は論理和 if (tf) { // true で jmpLab へジャンプ genLogExpr(node, c, 2, jmpLab, nxtLab); // || 式が false 時に直後へ } else { // false で jmpLab へジャンプ genLogExpr(node, c, 2, nxtLab, jmpLab); // || 式が true 時に直後へ } } else if (op==SyAND) { // 条件式は論理積 if (tf) { // true で jmpLab へジャンプ genLogExpr(node, c, 2, nxtLab, jmpLab); // && 式が true 時に直後へ } else { // true で jmpLabへジャンプ genLogExpr(node, c, 2, jmpLab, nxtLab); // && 式が false 時に直後へ } } else { genExpr(node, c); // 条件式を評価する boolJmp(tf, c, jmpLab); // 条件ジャンプ命令を生成 } printLab(nxtLab->no); // 使用されていればラベル生成 free(nxtLab); // Label を解放 free(c); // Expr を解放 }
/* * PreProcess - pre-process source file */ vi_rc PreProcess( const char *fn, sfile **sf, labels *lab ) { GENERIC_FILE gf; int i, token, k, len; sfile *tsf; char tmp[MAX_SRC_LINE], tmp2[MAX_SRC_LINE]; char tmp3[MAX_SRC_LINE]; bool ret; #ifdef VICOMP bool AppendingFlag = FALSE; #else #define AppendingFlag EditFlags.Appending #endif /* * get source file */ #ifdef VICOMP ret = SpecialOpen( fn, &gf ); #else if( EditFlags.CompileScript ) { EditFlags.OpeningFileToCompile = TRUE; ret = SpecialOpen( fn, &gf, FALSE ); EditFlags.OpeningFileToCompile = FALSE; } else { ret = SpecialOpen( fn, &gf, EditFlags.BoundData ); } #endif if( !ret ) { return( ERR_FILE_NOT_FOUND ); } /* * init control */ CSInit(); CurrentSrcLine = 0L; tsf = MemAlloc( sizeof( sfile ) ); tsf->next = NULL; tsf->prev = NULL; tsf->arg1 = NULL; tsf->arg2 = NULL; tsf->data = NULL; tsf->token = SRC_T_NULL; *sf = tmpTail = tsf; cLab = lab; /* * set up error handler */ i = setjmp( genExit ); if( i != 0 ) { SpecialFclose( &gf ); return( (vi_rc)i ); } /* * process each line */ while( SpecialFgets( tmp, MAX_SRC_LINE - 1, &gf ) >= 0 ) { /* * prepare this line */ CurrentSrcLine++; #ifndef VICOMP if( !EditFlags.ScriptIsCompiled ) { #endif RemoveLeadingSpaces( tmp ); k = strlen( tmp ); memcpy( tmp3, tmp, k + 1 ); if( (len = NextWord1( tmp, tmp2 )) <= 0 ) { continue; } if( tmp2[0] == '#' ) { continue; } hasVar = FALSE; for( i = 0; i < k; i++ ){ if( tmp3[i] == '%' ) { hasVar = TRUE; break; } } /* * if we are appending (ie, an append token was encounterd * before, stop tokenizing */ if( !AppendingFlag ) { token = Tokenize( SourceTokens, tmp2, TRUE ); #ifndef VICOMP if( token == SRC_T_VBJ__ ) { EditFlags.ScriptIsCompiled = TRUE; continue; } #endif } else { token = TOK_INVALID; } #ifndef VICOMP } else { len = NextWord1( tmp, tmp2 ); hasVar = (bool) tmp2[0] - '0'; token = atoi( &tmp2[1] ); } #endif /* * process recognized tokens */ if( token != TOK_INVALID ) { RemoveLeadingSpaces( tmp ); if( token > SRC_T_NULL ) { genItem( token, tmp ); continue; } /* * get parm */ AddString( &CurrentSrcData, tmp ); freeSrcData = TRUE; /* * process token */ switch( token ) { case SRC_T_EXPR: genExpr(); break; case SRC_T_LABEL: GenLabel( tmp ); break; case SRC_T_IF: CSIf(); break; case SRC_T_QUIF: CSQuif(); break; case SRC_T_ELSEIF: CSElseIf(); break; case SRC_T_ELSE: CSElse(); break; case SRC_T_ENDIF: CSEndif(); break; case SRC_T_LOOP: CSLoop(); break; case SRC_T_ENDLOOP: case SRC_T_ENDWHILE: CSEndLoop(); break; case SRC_T_WHILE: CSWhile(); break; case SRC_T_UNTIL: CSUntil(); break; case SRC_T_BREAK: CSBreak(); break; case SRC_T_CONTINUE: CSContinue(); break; default: genItem( token, NULL ); if( token == SRC_T_GOTO ) { #ifndef VICOMP if( EditFlags.ScriptIsCompiled ) { NextWord1( CurrentSrcData, tmp ); tmpTail->branchcond = atoi( CurrentSrcData ); strcpy( CurrentSrcData, tmp ); } else { #endif tmpTail->branchcond = COND_JMP; #ifndef VICOMP } #endif } tmpTail->data = CurrentSrcData; freeSrcData = FALSE; break; } if( freeSrcData ) { MemFree( CurrentSrcData ); } /* * set all other tokens to be processed at run time */ } else { #ifndef VICOMP if( EditFlags.ScriptIsCompiled ) { RemoveLeadingSpaces( tmp ); genItem( token, tmp ); continue; } #endif if( !AppendingFlag ) { token = Tokenize( TokensCmdLine, tmp2, TRUE ); } else { token = TOK_INVALID; } switch( token ) { case PCL_T_COMMANDWINDOW: case PCL_T_STATUSWINDOW: case PCL_T_COUNTWINDOW: case PCL_T_EDITWINDOW: case PCL_T_EXTRAINFOWINDOW: case PCL_T_FILECWINDOW: case PCL_T_LINENUMBERWINDOW: case PCL_T_DIRWINDOW: case PCL_T_FILEWINDOW: case PCL_T_SETWINDOW: case PCL_T_SETVALWINDOW: case PCL_T_MESSAGEWINDOW: case PCL_T_MENUWINDOW: case PCL_T_MENUBARWINDOW: case PCL_T_ENDWINDOW: case PCL_T_SETCOLOR: case PCL_T_MATCH: case PCL_T_DIMENSION: case PCL_T_BORDER: case PCL_T_HILIGHT: case PCL_T_TEXT: case PCL_T_ALIAS: case PCL_T_ABBREV: case PCL_T_MENU: case PCL_T_MENUITEM: case PCL_T_ENDMENU: case PCL_T_WHITESPACE: case PCL_T_SELECTION: case PCL_T_EOFTEXT: case PCL_T_KEYWORD: case PCL_T_OCTAL: case PCL_T_HEX: case PCL_T_INTEGER: case PCL_T_CHAR: case PCL_T_PREPROCESSOR: case PCL_T_SYMBOL: case PCL_T_INVALIDTEXT: case PCL_T_IDENTIFIER: case PCL_T_JUMPLABEL: case PCL_T_COMMENT: case PCL_T_FLOAT: case PCL_T_STRING: case PCL_T_VARIABLE: case PCL_T_FILETYPESOURCE: case PCL_T_ENDFILETYPESOURCE: case PCL_T_LOCATE: case PCL_T_MAP: case PCL_T_MAP_DMT: case PCL_T_MENUFILELIST: case PCL_T_MENULASTFILES: case PCL_T_DEFAULTWINDOW: case PCL_T_ACTIVEMENUWINDOW: case PCL_T_GREYEDMENUWINDOW: case PCL_T_ACTIVEGREYEDMENUWINDOW: RemoveLeadingSpaces( tmp ); token += SRC_T_NULL + 1; genItem( token, tmp ); break; case PCL_T_SET: token += SRC_T_NULL + 1; #ifdef VICOMP WorkLine->data[0] = 0; Set( tmp ); genItem( token, WorkLine->data ); #else if( EditFlags.CompileScript ) { vi_rc rc; WorkLine->data[0] = 0; rc = Set( tmp ); if( rc != ERR_NO_ERR ) { Error( GetErrorMsg( rc ) ); } genItem( token, WorkLine->data ); } else { genItem( token, tmp ); } #endif break; default: if( AppendingFlag ) { if( tmp3[0] == '.' && tmp3[1] == 0 ) { AppendingFlag = FALSE; } } else if( token == TOK_INVALID ) { /* * see if the current token is a Ex token. If * it isn't, then see if the next one is * (i.e., look for <n> append) */ token = Tokenize( TokensEx, tmp2, FALSE ); if( token == TOK_INVALID ) { if( NextWord1( tmp, tmp2 ) >= 0 ) { token = Tokenize( TokensEx, tmp2, FALSE ); if( token == EX_T_APPEND ) { AppendingFlag = TRUE; } } } } if( tmp3[0] == '>' ) { tmp3[0] = ' '; } genItem( TOK_INVALID, tmp3 ); break; } } } SpecialFclose( &gf ); AppendingFlag = FALSE; return( CSFini() ); } /* PreProcess */
// 代入式 static void genAsExpr(int node, struct Expr* c) { genExpr(syGetRVal(node), c); // 右辺を評価しスタックに積む genBoolExpr(syGetLVal(node), c); // 左辺(代入先)を評価する store(c); // ST 左辺 c->place = STKD; // まだ値はスタックに残る }