Changeset 76 in dev for BasicCompiler32/NumOpe.cpp


Ignore:
Timestamp:
Mar 21, 2007, 9:26:56 PM (17 years ago)
Author:
dai_9181
Message:

TYPEINFO→Typeへのリファクタリングを実施。32bitが未完成。

File:
1 edited

Legend:

Unmodified
Added
Removed
  • BasicCompiler32/NumOpe.cpp

    r75 r76  
    6767}
    6868
    69 void NewStringObject(LPSTR lpszText){
     69void NewStringObject( const char *str ){
    7070    ///////////////////////////////////////////////////////
    7171    // lpszTextを元にStringオブジェクトを生成し、
     
    7373    ///////////////////////////////////////////////////////
    7474
    75     char *parameter = (char *)malloc( lstrlen( lpszText ) + 32 );
    76     sprintf( parameter, "\"%s\"%c%c*Char", lpszText, 1, ESC_AS );
     75    char *parameter = (char *)malloc( lstrlen( str ) + 32 );
     76    sprintf( parameter, "\"%s\"%c%c*Char", str, 1, ESC_AS );
    7777    SetStringQuotes( parameter );
    7878
    7979    extern CClass *pobj_StringClass;
    80     Type baseTypeInfo = { DEF_OBJECT, (LONG_PTR)pobj_StringClass };
    81     Operator_New( *pobj_StringClass, "", parameter, baseTypeInfo );
     80    Operator_New( *pobj_StringClass, "", parameter, Type( DEF_OBJECT, *pobj_StringClass ) );
    8281
    8382    free( parameter );
     
    8584
    8685
    87 int NumOpe(const char *Command,int BaseType,LONG_PTR lpBaseIndex,LONG_PTR *plpIndex,BOOL *pbUseHeap){
    88     extern HANDLE hHeap;
     86bool NumOpe( const char *expression,
     87            const Type &baseType,
     88            Type &resultType,
     89            BOOL *pbUseHeap ){
     90
    8991    int i,i2,i3,i4;
    90     char temporary[8192],temp2[1024],temp3[1024];
    91 
    92     if(Command[0]=='\0'){
     92    char temporary[1024],temp2[1024],temp3[1024];
     93
     94    if(expression[0]=='\0'){
    9395        SetError(1,NULL,cp);
    94         return -1;
    95     }
    96 
    97     if(Command[0]==1&& Command[1]==ESC_NEW ){
     96        return false;
     97    }
     98
     99    if(expression[0]==1&& expression[1]==ESC_NEW ){
    98100        //New演算子(オブジェクト生成)
    99         Type baseTypeInfo = { BaseType, lpBaseIndex };
    100         int resultType = Operator_New(Command+2,plpIndex, baseTypeInfo );
    101 
    102         return resultType;
     101
     102        if( !Operator_New( expression+2, baseType, resultType ) ){
     103            return false;
     104        }
     105
     106        return true;
    103107    }
    104108
     
    112116    long stack[255];
    113117    int pnum;
    114     if(!GetNumOpeElements(Command,&pnum,values,calc,stack)){
     118    if(!GetNumOpeElements(expression,&pnum,values,calc,stack)){
    115119        for(i=0;i<pnum;i++){
    116120            if(values[i]) HeapDefaultFree(values[i]);
    117121        }
    118         return 0;
     122        return false;
    119123    }
    120124
     
    146150    double dbl;
    147151    int sp;
    148     int type[255];
     152    int type_stack[255];
    149153    LONG_PTR index_stack[255];
    150154    BOOL bUseHeap[255];
     
    155159
    156160        if(idCalc){
    157             if(type[sp-2]==DEF_OBJECT){
     161            if(type_stack[sp-2]==DEF_OBJECT){
    158162                //オーバーロードされたオペレータを呼び出す
    159                 Type BaseTypeInfo={BaseType,lpBaseIndex};
    160                 i2=CallOperatorProc(idCalc,&BaseTypeInfo,type,index_stack,bUseHeap,sp);
     163                i2=CallOperatorProc(idCalc,baseType,type_stack,index_stack,bUseHeap,sp);
    161164                if(i2==0){
    162165                    if(idCalc==CALC_EQUAL) lstrcpy(temp2,"==");
     
    171174            }
    172175
    173             if(!CheckCalcType(idCalc,type,sp)) goto error;
     176            if(!CheckCalcType(idCalc,type_stack,sp)) goto error;
    174177        }
    175178
     
    192195StrLiteral:
    193196
    194                     if(BaseType==DEF_OBJECT){
    195                         CClass *pobj_Class;
    196                         pobj_Class=(CClass *)lpBaseIndex;
    197                         Type BaseTypeInfo = {BaseType,lpBaseIndex};
    198                         if(IsStringObjectType(BaseTypeInfo)){
    199                             //要求タイプがオブジェクトであり、Stringの受け入れが可能な場合
     197                    if( baseType.IsObject() ){
     198                        if( baseType.IsStringObject() ){
     199                            //要求タイプがStringのとき
    200200
    201201                            //String型オブジェクトを生成
     
    203203
    204204                            extern CClass *pobj_StringClass;
    205                             type[sp]=DEF_OBJECT;
     205                            type_stack[sp]=DEF_OBJECT;
    206206                            index_stack[sp]=(LONG_PTR)pobj_StringClass;
    207207                            bLiteralCalculation=0;
     
    213213
    214214
    215                     type[sp]=typeOfPtrChar;
    216                     index_stack[sp]=LITERAL_STRING;
     215                    type_stack[sp]=typeOfPtrChar;
    217216                    bLiteralCalculation=0;
    218217
     
    252251                        i4=GetStringInPare_RemovePare(temp2,term+i2+1);
    253252
    254                         int idProc;
    255253                        void *pInfo;
    256                         idProc=GetProc(temporary,&pInfo);
    257 
     254                        int idProc=GetProc(temporary,(void **)&pInfo);
     255
     256                        Type resultType;
    258257                        if(idProc){
    259258                            //閉じカッコ")"に続く文字がNULLでないとき
     
    272271                            ////////////////
    273272
    274                             i2=CallProc(idProc,pInfo,temporary,temp2,&index_stack[sp]);
    275                             if(i2==-1){
     273                            CallProc(idProc,pInfo,temporary,temp2,resultType);
     274                            if(resultType.IsNull()){
    276275                                //戻り値が存在しないとき
    277276                                for(i2=2;;i2++){
     
    292291
    293292                            //大きな型への暗黙の変換
    294                             type[sp]=AutoBigCast(BaseType,i2);
     293                            type_stack[sp]=AutoBigCast(baseType.GetBasicType(),resultType.GetBasicType());
     294                            index_stack[sp] = resultType.GetIndex();
    295295                            bLiteralCalculation=0;
    296296
    297297                            //スタックへプッシュ
    298                             PushReturnValue(i2);
    299 
    300                             if(Is64Type(type[sp])&&IsWholeNumberType(i2)&&GetTypeSize(i2,-1)<=sizeof(long)){
    301                                 //必要に応じて64ビット拡張
    302                                 ExtendStackTo64(i2);
     298                            PushReturnValue( resultType.GetBasicType() );
     299
     300                            if( Is64Type(type_stack[sp])
     301                                && resultType.IsWhole()
     302                                && resultType.GetBasicSize() <= sizeof(long) ){
     303                                    //必要に応じて64ビット拡張
     304                                    ExtendStackTo64( resultType.GetBasicType() );
    303305                            }
    304306
    305                             if(i2==DEF_STRUCT){
     307                            if( resultType.IsStruct() ){
    306308                                //構造体が戻ったときはヒープ領域にインスタンスが格納されている
    307309                                //※後にfreeする必要あり
     
    321323
    322324                            //マクロ関数の場合
    323                             type[sp]=NumOpe(temp3,0,0,&index_stack[sp]);
    324 
    325                             if(!IS_LITERAL(index_stack[sp])){
     325                            NumOpe(temp3,Type(),resultType);
     326
     327                            if(!IS_LITERAL(resultType.GetIndex())){
    326328                                //リテラル値ではなかったとき
    327329                                bLiteralCalculation=0;
    328330                            }
    329331
     332                            type_stack[sp] = resultType.GetBasicType();
     333                            index_stack[sp] = resultType.GetIndex();
     334
    330335                            sp++;
    331336                            break;
     
    335340
    336341
    337 
     342                    //インデクサ(getアクセサ)
    338343                    char variable[VN_SIZE],array_element[VN_SIZE];
    339                     CClass *pobj_c;
    340344                    GetArrayElement(term,variable,array_element);
    341345                    if(array_element[0]){
    342                         i2=GetVarType(variable,(LONG_PTR *)&pobj_c,0);
    343                         if(i2==DEF_OBJECT){
    344                             Type RetTypeInfo;
    345                             CallIndexerGetterProc(pobj_c,variable,array_element,RetTypeInfo);
    346                             type[sp]=RetTypeInfo.type;
    347                             index_stack[sp]=RetTypeInfo.u.lpIndex;
     346                        Type resultType;
     347                        GetVarType(variable,resultType,0);
     348                        if( resultType.IsObject() ){
     349                            CallIndexerGetterProc(&resultType.GetClass(),variable,array_element,resultType);
     350                            type_stack[sp]=resultType.GetBasicType();
     351                            index_stack[sp]=resultType.GetIndex();
    348352                            bLiteralCalculation=0;
    349353
     
    359363                    // Nothing
    360364                    if( lstrcmp( term, "Nothing" ) == 0 ){
    361                         type[sp] = DEF_OBJECT;
    362                         if( BaseType == DEF_OBJECT ){
    363                             index_stack[sp] = lpBaseIndex;
     365                        type_stack[sp] = DEF_OBJECT;
     366                        if( baseType.IsObject() ){
     367                            index_stack[sp] = baseType.GetIndex();
    364368                        }
    365369                        else{
     
    377381
    378382
     383                    if( (string)term=="value"){
     384                        int test=0;
     385                    }
     386
    379387
    380388                    RELATIVE_VAR RelativeVar;
     389                    Type varType;
    381390                    if(GetVarOffset(
    382391                        false,  //エラー表示あり
    383392                        false,  //読み込み専用
    384                         term,&i2,&RelativeVar,&index_stack[sp])){
     393                        term,
     394                        &RelativeVar,varType)){
    385395                        //////////
    386396                        // 変数
     
    388398
    389399                        //大きな型への暗黙の変換
    390                         type[sp]=AutoBigCast(BaseType,i2);
     400                        type_stack[sp]=AutoBigCast(baseType.GetBasicType(),varType.GetBasicType());
     401                        index_stack[sp] = varType.GetIndex();
    391402                        bLiteralCalculation=0;
    392403
    393                         if(i2&FLAG_PTR){
     404                        if(varType.GetBasicType()&FLAG_PTR){
    394405                            //配列ポインタ
    395                             type[sp]=GetPtrType(i2^FLAG_PTR,index_stack[sp]);
     406                            type_stack[sp]=GetPtrType(varType.GetBasicType()^FLAG_PTR);
    396407
    397408                            SetVarPtrToEax(&RelativeVar);
     
    400411                            op_push(REG_EAX);
    401412                        }
    402                         else if(i2==DEF_DOUBLE||
    403                             i2==DEF_INT64||
    404                             i2==DEF_QWORD){
     413                        else if( varType.IsStruct() ){
     414                            //構造体ポインタをeaxへ格納(構造体は値型)
     415                            SetVarPtrToEax(&RelativeVar);
     416
     417                            //push eax
     418                            op_push(REG_EAX);
     419                        }
     420                        else if( varType.GetBasicSize() == sizeof(_int64) ){
    405421                            //64ビット型
    406422                            PushDoubleVariable(&RelativeVar);
    407423                        }
    408                         else if(i2==DEF_LONG||i2==DEF_DWORD||i2==DEF_SINGLE||
    409                             IsPtrType(i2) || i2==DEF_OBJECT){
     424                        else if( varType.GetBasicSize() == sizeof(long) ){
    410425                            //32ビット型
    411426                            PushLongVariable(&RelativeVar);
    412427                        }
    413                         else if(i2==DEF_INTEGER || (isUnicode&&i2==DEF_CHAR)){
     428                        else if( varType.IsInteger() ){
    414429                            PushIntegerVariable(&RelativeVar);
    415430                        }
    416                         else if(i2==DEF_WORD){
     431                        else if( varType.IsWord() ){
    417432                            PushWordVariable(&RelativeVar);
    418433                        }
    419                         else if(i2==DEF_SBYTE || (isUnicode==false&&i2==DEF_CHAR)){
     434                        else if( varType.IsSByte() ){
    420435                            PushCharVariable(&RelativeVar);
    421436                        }
    422                         else if(i2==DEF_BYTE||i2==DEF_BOOLEAN){
     437                        else if( varType.IsByte() || varType.IsBoolean() ){
    423438                            PushByteVariable(&RelativeVar);
    424439                        }
    425                         else if(i2==DEF_STRUCT){
    426                             //構造体ポインタをeaxへ格納(構造体は値型)
    427                             SetVarPtrToEax(&RelativeVar);
    428 
    429                             //push eax
    430                             op_push(REG_EAX);
    431                         }
    432440                        else SetError(11,term,cp);
    433441
    434                         if(Is64Type(type[sp])&&IsWholeNumberType(i2)&&GetTypeSize(i2,-1)<=sizeof(long)){
     442                        if( Is64Type(type_stack[sp])
     443                            && varType.IsWhole()
     444                            && varType.GetBasicSize()<=sizeof(long)){
    435445                            //必要に応じて64ビット拡張
    436                             ExtendStackTo64(i2);
     446                                ExtendStackTo64( varType.GetBasicType() );
    437447                        }
    438448
     
    448458                    i3 = CDBConst::obj.GetType(term);
    449459                    if(i3){
    450                         type[sp]=i3;
     460                        type_stack[sp]=i3;
    451461                        if(IsRealNumberType(i3)){
    452462                            //実数
     
    483493                    i3=GetTypeFixed(term,&lp);
    484494                    if(i3!=-1){
    485                         type[sp]=i3|FLAG_CAST;
     495                        type_stack[sp]=i3|FLAG_CAST;
    486496                        index_stack[sp]=lp;
    487497                        sp++;
     
    500510
    501511                    if(GetSubHash(VarName,0)){
    502                         Type RetTypeInfo;
    503                         CallPropertyMethod(term,NULL,&RetTypeInfo);
     512                        Type resultType;
     513                        CallPropertyMethod(term,NULL,resultType);
    504514
    505515                        //大きな型への暗黙の変換
    506                         type[sp]=AutoBigCast(BaseType,RetTypeInfo.type);
    507 
    508                         index_stack[sp]=RetTypeInfo.u.lpIndex;
     516                        type_stack[sp]=AutoBigCast(baseType.GetBasicType(),resultType.GetBasicType());
     517                        index_stack[sp]=resultType.GetIndex();
    509518                        bLiteralCalculation=0;
    510519
    511520                        //スタックへプッシュ
    512                         PushReturnValue(RetTypeInfo.type);
    513 
    514                         if(type[sp]==DEF_STRUCT){
     521                        PushReturnValue( resultType.GetBasicType() );
     522
     523                        if(type_stack[sp]==DEF_STRUCT){
    515524                            //構造体が戻ったときはヒープ領域にインスタンスが格納されている
    516525                            //※後にfreeする必要あり
     
    527536                    bError=1;
    528537                    SetError(3,term,cp);
    529                     type[sp]=DEF_DOUBLE;
     538                    type_stack[sp]=DEF_DOUBLE;
    530539                }
    531540                else{
    532541                    //リテラル値
    533                     type[sp]=GetLiteralValue(term,&i64data,BaseType);
     542                    type_stack[sp]=GetLiteralValue(term,&i64data,baseType.GetBasicType());
    534543Literal:
    535                     if(type[sp]==DEF_INT64||
    536                         type[sp]==DEF_QWORD||
    537                         type[sp]==DEF_DOUBLE){
     544                    if(type_stack[sp]==DEF_INT64||
     545                        type_stack[sp]==DEF_QWORD||
     546                        type_stack[sp]==DEF_DOUBLE){
    538547                        //64ビット(符号有り整数/実数)
    539548
     
    544553                        op_push_V(*(long *)(&i64data));
    545554                    }
    546                     else if(type[sp]==DEF_SINGLE){
     555                    else if(type_stack[sp]==DEF_SINGLE){
    547556                        //single実数
    548557
     
    566575
    567576                    //リテラル値の種類
    568                     if(Is64Type(type[sp])==0&&IsRealNumberType(type[sp])==0){
     577                    if(Is64Type(type_stack[sp])==0&&IsRealNumberType(type_stack[sp])==0){
    569578                        //整数(符号有り/無し)
    570579
     
    579588                //value[sp-2] xor= value[sp-1]
    580589                //xor演算
    581                 if(!Calc_Xor(type,index_stack,&sp)) goto error;
     590                if(!Calc_Xor(type_stack,index_stack,&sp)) goto error;
    582591                break;
    583592            case CALC_OR:
    584593                //value[sp-2] or= value[sp-1]
    585594                //or演算
    586                 if(!Calc_Or(type,index_stack,&sp)) goto error;
     595                if(!Calc_Or(type_stack,index_stack,&sp)) goto error;
    587596                break;
    588597            case CALC_AND:
    589598                //value[sp-2] and= value[sp-1]
    590599                //and演算
    591                 if(!Calc_And(type,index_stack,&sp)) goto error;
     600                if(!Calc_And(type_stack,index_stack,&sp)) goto error;
    592601                break;
    593602            case CALC_NOT:
    594603                //value[sp-1]=Not value[sp-1]
    595604                //NOT演算子
    596                 if(!Calc_Not(type,sp)) goto error;
     605                if(!Calc_Not(type_stack,sp)) goto error;
    597606                break;
    598607
     
    600609            case CALC_PE:
    601610                //value[sp-2]<=value[sp-1]
    602                 if(!Calc_Relation_PE(type,index_stack,&sp)) goto error;
     611                if(!Calc_Relation_PE(type_stack,index_stack,&sp)) goto error;
    603612                break;
    604613            case CALC_QE:
    605614                //value[sp-2]>=value[sp-1]
    606                 if(!Calc_Relation_QE(type,index_stack,&sp)) goto error;
     615                if(!Calc_Relation_QE(type_stack,index_stack,&sp)) goto error;
    607616                break;
    608617            case CALC_P:
    609618                //value[sp-2]<value[sp-1]
    610                 if(!Calc_Relation_P(type,index_stack,&sp)) goto error;
     619                if(!Calc_Relation_P(type_stack,index_stack,&sp)) goto error;
    611620                break;
    612621            case CALC_Q:
    613622                //value[sp-2]>value[sp-1]
    614                 if(!Calc_Relation_Q(type,index_stack,&sp)) goto error;
     623                if(!Calc_Relation_Q(type_stack,index_stack,&sp)) goto error;
    615624                break;
    616625            case CALC_NOTEQUAL:
    617626                //value[sp-2]<>value[sp-1]
    618                 if(!Calc_Relation_NotEqual(type,&sp)) goto error;
     627                if(!Calc_Relation_NotEqual(type_stack,&sp)) goto error;
    619628                break;
    620629            case CALC_EQUAL:
    621630                //value[sp-2]=value[sp-1]
    622                 if(!Calc_Relation_Equal(type,&sp)) goto error;
     631                if(!Calc_Relation_Equal(type_stack,&sp)) goto error;
    623632                break;
    624633
     
    626635            case CALC_SHL:
    627636                //value[sp-2]=value[sp-2]<<value[sp-1]
    628                 if(!Calc_SHL(type,&sp)) goto error;
     637                if(!Calc_SHL(type_stack,&sp)) goto error;
    629638                break;
    630639            case CALC_SHR:
    631640                //value[sp-2]=value[sp-2]>>value[sp-1]
    632                 if(!Calc_SHR(type,&sp)) goto error;
     641                if(!Calc_SHR(type_stack,&sp)) goto error;
    633642                break;
    634643
     
    637646            case CALC_SUBTRACTION:
    638647            case CALC_PRODUCT:
    639                 if(!CalcTwoTerm_Arithmetic(idCalc,type,index_stack,&sp)) goto error;
     648                if(!CalcTwoTerm_Arithmetic(idCalc,type_stack,index_stack,&sp)) goto error;
    640649                break;
    641650
     
    643652                //value[sp-2]%=value[sp-1]
    644653                //剰余演算
    645                 if(!Calc_Mod(type,&sp)) goto error;
     654                if(!Calc_Mod(type_stack,&sp)) goto error;
    646655                break;
    647656            case CALC_QUOTIENT:
    648657                //value[sp-2]/=value[sp-1];
    649658                //除算
    650                 if(!Calc_Divide(type,&sp,BaseType)) goto error;
     659                if(!Calc_Divide(type_stack,&sp,baseType.GetBasicType())) goto error;
    651660                break;
    652661            case CALC_INTQUOTIENT:
    653662                //value[sp-2]/=value[sp-1]
    654663                //整数除算
    655                 if(!Calc_IntDivide(type,index_stack,&sp)) goto error;
     664                if(!Calc_IntDivide(type_stack,index_stack,&sp)) goto error;
    656665                break;
    657666            case CALC_MINUSMARK:
    658667                //value[sp-1]=-value[sp-1]
    659668                //符号反転
    660                 if(!Calc_MinusMark(type,sp)) goto error;
     669                if(!Calc_MinusMark(type_stack,sp)) goto error;
    661670                index_stack[sp-1]=-1;
    662671                break;
    663672            case CALC_POWER:
    664673                //べき乗演算(浮動小数点演算のみ)
    665                 if(!Calc_Power(type,&sp)) goto error;
     674                if(!Calc_Power(type_stack,&sp)) goto error;
    666675                break;
    667676            case CALC_AS:
    668677                //キャスト
    669                 if(!Calc_Cast(type,index_stack,&sp)) goto error;
     678                if(!Calc_Cast(type_stack,index_stack,&sp)) goto error;
    670679                break;
    671680
    672681            case CALC_BYVAL:
    673682                //ポインタ型→参照型
    674                 if( PTR_LEVEL( type[sp-1] ) <= 0 ){
     683                if( PTR_LEVEL( type_stack[sp-1] ) <= 0 ){
    675684                    //ポインタ型ではないとき
    676685                    SetError( 3, NULL, cp );
     
    678687                }
    679688
    680                 type[sp-1] = PTR_LEVEL_DOWN( type[sp-1] );
     689                type_stack[sp-1] = PTR_LEVEL_DOWN( type_stack[sp-1] );
    681690
    682691                break;
     
    697706    if(bLiteralCalculation){
    698707        //右辺値が数値の定数式の場合
    699         LONG_PTR lpClassIndex;
    700         i2=StaticCalculation(true, Command,BaseType,&i64data,&lpClassIndex);
     708        Type resultType;
     709        StaticCalculation(true, expression,baseType.GetBasicType(),&i64data,resultType);
    701710
    702711        obp=BeforeObp;
     
    705714        pobj_Reloc->copy(pobj_BackReloc);
    706715
    707         if(i2==DEF_INT64||
    708             i2==DEF_QWORD||
    709             i2==DEF_DOUBLE){
     716        if( resultType.GetBasicSize() == sizeof(_int64) ){
    710717            //64ビット(符号有り整数/実数)
    711718
     
    716723            op_push_V(*(long *)(&i64data));
    717724        }
    718         else if(i2==DEF_SINGLE){
     725        else if( resultType.IsSingle() ){
    719726            //single実数
    720727
     
    733740            i3=(long)i64data;
    734741
    735             if(i2==DEF_SBYTE||i2==DEF_BYTE||i2==DEF_BOOLEAN || (isUnicode==false&&i2==DEF_CHAR)) i3=i3&0x000000FF;
    736             if(i2==DEF_INTEGER||i2==DEF_WORD || (isUnicode&&i2==DEF_CHAR)) i3=i3&0x0000FFFF;
     742            if(resultType.GetBasicSize()==sizeof(char)) i3=i3&0x000000FF;
     743            if(resultType.GetBasicSize()==sizeof(short)) i3=i3&0x0000FFFF;
    737744
    738745            //push term
     
    740747        }
    741748
    742         type[0]=i2;
    743         index_stack[0]=lpClassIndex;
     749        type_stack[0]=resultType.GetBasicType();
     750        index_stack[0]=resultType.GetIndex();
    744751    }
    745752    else{
     
    748755    }
    749756
    750     if(plpIndex) *plpIndex=index_stack[0];
    751757    if(pbUseHeap) *pbUseHeap=bUseHeap[0];
    752758
    753     int RetType;
    754     RetType=type[0];
     759    resultType.SetType( type_stack[0], index_stack[0] );
     760
     761    bool isSuccessful = true;
    755762    goto finish;
    756763
    757764
    758765error:
    759     RetType=-1;
     766    isSuccessful = false;
    760767    goto finish;
    761768
     
    770777    delete pobj_BackReloc;
    771778
    772     return RetType;
     779    return isSuccessful;
    773780}
Note: See TracChangeset for help on using the changeset viewer.