source: dev/trunk/ab5.0/abdev/compiler_x86/Compile_Var.cpp@ 494

Last change on this file since 494 was 465, checked in by dai_9181, 17 years ago

Messenger/ErrorMessengerクラスを導入。SetError関数によるエラー生成を廃止した。

File size: 35.2 KB
Line 
1#include "stdafx.h"
2
3#include <LexicalScope.h>
4#include <CodeGenerator.h>
5#include <Compiler.h>
6#include <Variable.h>
7
8#include "../BasicCompiler_Common/common.h"
9#include "Opcode.h"
10
11//変数
12// TODO: xml未完成
13int AllLocalVarSize;
14
15
16void SetRelativeOffset( Type &resultType, RELATIVE_VAR *pRelativeVar,const char *lpPtrOffset){
17 PushLongVariable(pRelativeVar);
18
19 Type type;
20 NumOpe( lpPtrOffset, Type(), type );
21 ChangeTypeToLong( type.GetBasicType() );
22
23 //pop ebx
24 compiler.codeGenerator.op_pop(REG_EBX);
25
26 if( resultType.PtrLevel() ){
27 resultType.PtrLevelDown();
28
29 int typeSize = resultType.GetSize();
30 if(typeSize>=2){
31 //imul ebx,i2
32 compiler.codeGenerator.op_imul_RV( REG_EBX, typeSize );
33 }
34 }
35 else{
36 //エラー
37 compiler.errorMessenger.Output(1,NULL,cp);
38 return;
39 }
40
41 //pop ecx
42 compiler.codeGenerator.op_pop(REG_ECX);
43
44 //add ecx,ebx
45 compiler.codeGenerator.op_add_RR( REG_ECX, REG_EBX );
46}
47void SetRelativeOffset( RELATIVE_VAR &relativeVar ){
48 if(relativeVar.dwKind==VAR_DIRECTMEM){
49 //mov ecx,dword ptr[ecx]
50 compiler.codeGenerator.op_mov_RM( sizeof(long), REG_ECX, REG_ECX, 0, MOD_BASE );
51 }
52 else{
53 //直接参照に切り替え
54 SetVarPtrToEax(&relativeVar);
55 relativeVar.dwKind=VAR_DIRECTMEM;
56
57 //mov ecx,dword ptr[eax]
58 compiler.codeGenerator.op_mov_RM( sizeof(long), REG_ECX, REG_EAX, 0, MOD_BASE );
59 }
60}
61bool GetArrayOffset(const Subscripts &subscripts,char *array, const Type &type){
62 extern HANDLE hHeap;
63 int i,i2,i3,i4;
64 char temporary[VN_SIZE],*pParm[MAX_PARMS];
65
66 for(i=0,i2=0,i3=0;;i++,i2++){
67 if(array[i]=='('){
68 i4=GetStringInPare(temporary+i2,array+i);
69 i+=i4-1;
70 i2+=i4-1;
71 continue;
72 }
73 if(array[i]=='['){
74 i4=GetStringInBracket(temporary+i2,array+i);
75 i+=i4-1;
76 i2+=i4-1;
77 continue;
78 }
79 if(array[i]==','||array[i]=='\0'){
80 if( i3 >= (int)subscripts.size() )
81 {
82 for(i3--;i3>=0;i3--) HeapDefaultFree(pParm[i3]);
83 return 0;
84 }
85
86 temporary[i2]=0;
87
88 pParm[i3]=(char *)HeapAlloc(hHeap,0,lstrlen(temporary)+1);
89 lstrcpy(pParm[i3],temporary);
90
91 i3++;
92
93 if(array[i]=='\0'){
94 if( i3 < (int)subscripts.size() )
95 {
96 for(i3--;i3>=0;i3--) HeapDefaultFree(pParm[i3]);
97 return 0;
98 }
99 break;
100 }
101
102 i2=-1;
103 continue;
104 }
105 temporary[i2]=array[i];
106 }
107
108 //push ecx
109 compiler.codeGenerator.op_push(REG_ECX);
110
111 //push 0
112 compiler.codeGenerator.op_push_V(0);
113
114 for(i=i3-1;i>=0;i--){
115 Type tempType;
116 bool isNeedHeapFreeStructure;
117 NumOpe( pParm[i], Type( DEF_LONG ), tempType, &isNeedHeapFreeStructure );
118 if( tempType.IsObject() )
119 {
120 //キャスト演算子のオーバーロードに対応する
121 CallCastOperatorProc(
122 tempType,
123 isNeedHeapFreeStructure, Type(DEF_LONG) );
124 tempType.SetBasicType( DEF_LONG );
125 }
126 ChangeTypeToLong( tempType.GetBasicType() );
127
128 //pop eax
129 compiler.codeGenerator.op_pop(REG_EAX);
130
131 for( i2=i+1, i4=1; i2<i3; i2++ )
132 {
133 i4*=subscripts[i2]+1;
134 }
135
136 //imul eax,i4
137 compiler.codeGenerator.op_imul_RV( REG_EAX, i4 );
138
139 //add dword ptr[esp],eax
140 compiler.codeGenerator.PutOld(
141 (char)0x01,
142 (char)0x04,
143 (char)0x24
144 );
145
146 HeapDefaultFree(pParm[i]);
147 }
148
149 //pop eax
150 compiler.codeGenerator.op_pop(REG_EAX);
151
152 //imul eax,TypeSize
153 compiler.codeGenerator.op_imul_RV( REG_EAX, type.GetSize() );
154
155 //pop ecx
156 compiler.codeGenerator.op_pop(REG_ECX);
157
158 //add ecx,eax
159 compiler.codeGenerator.op_add_RR( REG_ECX, REG_EAX );
160
161 return 1;
162}
163bool _member_offset(bool isErrorEnabled, bool isWriteAccess, const Type &classType, const char *member, RELATIVE_VAR *pRelativeVar, Type &resultType, BOOL bPrivateAccess)
164{
165 const CClass &objClass = classType.GetClass();
166
167 //////////////////////////////////////
168 // クラス、配列の構成要素を解析する
169 //////////////////////////////////////
170
171 char VarName[VN_SIZE]; //変数名
172 char array[VN_SIZE]; //第1次配列
173 char lpPtrOffset[VN_SIZE]; //第2次配列
174 char NestMember[VN_SIZE]; //入れ子メンバ
175 ReferenceKind refType;
176 lstrcpy(VarName,member);
177 if(!GetVarFormatString(VarName,array,lpPtrOffset,NestMember,refType)) return false;
178
179
180 ////////////////////////////
181 // メンバオフセットを取得
182 ////////////////////////////
183
184 const CMember *pMember = objClass.FindDynamicMember( VarName );
185 if( !pMember )
186 {
187 if(isErrorEnabled) compiler.errorMessenger.Output(103,VarName,cp);
188 return false;
189 }
190
191 int offset = objClass.GetMemberOffset( VarName );
192
193
194 //アクセシビリティをチェック
195 if(&objClass==compiler.pCompilingClass){
196 //同一クラスオブジェクトの場合はプライベートアクセスを容認する
197 if(pMember->IsNoneAccess()){
198 if(isErrorEnabled) compiler.errorMessenger.Output(107,VarName,cp);
199 return false;
200 }
201 }
202 else{
203 if((bPrivateAccess==0&&pMember->IsPrivate())||
204 pMember->IsNoneAccess()){
205 if(isErrorEnabled) compiler.errorMessenger.Output(107,VarName,cp);
206 return false;
207 }
208 else if(bPrivateAccess==0&&pMember->IsProtected()){
209 if(isErrorEnabled) compiler.errorMessenger.Output(108,VarName,cp);
210 return false;
211 }
212 }
213
214 //Const定義の場合は書き込みアクセスを制限する
215 //※コンストラクタをコンパイル中の場合は例外的に許可する
216 if( pMember->IsConst() && //定数メンバである
217 isWriteAccess && //書き込みアクセスを要求されている
218 objClass.IsCompilingConstructor() == false //コンストラクタ コンパイル中を除く
219 ){
220 //Const定義の変数に書き込みアクセスをしようとした場合
221 compiler.errorMessenger.Output(61,VarName,cp);
222 }
223
224 resultType = pMember->GetType();
225
226 // 型パラメータを解決
227 ResolveFormalGenericTypeParameter( resultType, classType );
228
229
230 //ポインタ変数の場合
231 if( resultType.IsPointer() ){
232 if( pMember->GetSubscripts().size() == 0 ){
233 lstrcpy(lpPtrOffset,array);
234 array[0]=0;
235 }
236 }
237 else{
238 if(lpPtrOffset[0]){
239 if(isErrorEnabled) compiler.errorMessenger.Output(16,member,cp);
240 return false;
241 }
242 }
243
244 if(offset){
245 //add ecx,offset
246 compiler.codeGenerator.op_add_RV( REG_ECX, offset );
247 }
248
249 if(array[0]){
250 //配列オフセット
251 if(!GetArrayOffset(pMember->GetSubscripts(),array,pMember->GetType())){
252 if(isErrorEnabled) compiler.errorMessenger.Output(14,member,cp);
253 return false;
254 }
255 }
256 else if( pMember->GetSubscripts().size() > 0 ){
257 resultType.SetBasicType( resultType.GetBasicType() | FLAG_PTR );
258 }
259
260 if(NestMember[0]){
261 //入れ子構造の場合
262
263 if( resultType.IsObject() || resultType.IsStruct() ){
264 if( refType != RefDot ){
265 if(isErrorEnabled) compiler.errorMessenger.Output(104,member,cp);
266 return false;
267 }
268
269 if( resultType.IsObject() ){
270 // 参照内容へのポインタを抽出
271 SetRelativeOffset( *pRelativeVar );
272 }
273 }
274 else if( resultType.IsObjectPtr() || resultType.IsStructPtr() ){
275 //構造体ポインタ型メンバ変数
276
277 if(lpPtrOffset[0]){
278 //pObj[n].member
279 if( ( resultType.IsObjectPtr() || resultType.IsStructPtr() )
280 && refType != RefDot ){
281 if(isErrorEnabled) compiler.errorMessenger.Output(104,member,cp);
282 return false;
283 }
284
285 //直接参照に切り替え
286 SetRelativeOffset(resultType,pRelativeVar,lpPtrOffset);
287 pRelativeVar->dwKind=VAR_DIRECTMEM;
288
289 lpPtrOffset[0]=0;
290 }
291 else{
292 //pObj->member
293 if( ( resultType.IsObjectPtr() || resultType.IsStructPtr() )
294 && refType != RefPointer ){
295 if(isErrorEnabled) compiler.errorMessenger.Output(104,member,cp);
296 return false;
297 }
298
299 SetRelativeOffset( *pRelativeVar );
300 }
301 }
302 else if( resultType.GetBasicType() == MAKE_PTR_TYPE(DEF_OBJECT,2)
303 || resultType.GetBasicType() == MAKE_PTR_TYPE(DEF_STRUCT,2)){
304 //構造体ポインタのポインタ型メンバ変数
305
306 if(lpPtrOffset[0]){
307 //ppObj[n]->member
308 if( refType != RefPointer ){
309 if(isErrorEnabled) compiler.errorMessenger.Output(104,member,cp);
310 return false;
311 }
312
313 //直接参照に切り替え
314 SetRelativeOffset(resultType,pRelativeVar,lpPtrOffset);
315 pRelativeVar->dwKind=VAR_DIRECTMEM;
316
317 lpPtrOffset[0]=0;
318
319 //mov ecx,dword ptr[ecx]
320 compiler.codeGenerator.op_mov_RM( sizeof(long), REG_ECX, REG_ECX, 0, MOD_BASE );
321 }
322 else{
323 if(isErrorEnabled) compiler.errorMessenger.Output(104,member,cp);
324 return false;
325 }
326 }
327
328 if(!_member_offset(
329 isErrorEnabled,
330 isWriteAccess,
331 pMember->GetType(),
332 NestMember,
333 pRelativeVar,
334 resultType,
335 0)) return false;
336 }
337
338 if(lpPtrOffset[0]){
339 SetRelativeOffset(resultType,pRelativeVar,lpPtrOffset);
340 pRelativeVar->dwKind=VAR_DIRECTMEM;
341 }
342
343 return true;
344}
345
346int LocalVar_ThisPtrOffset;
347void SetThisPtrToReg(int reg){
348 //自身のオブジェクトのThisポインタをregにコピー
349
350 RELATIVE_VAR RelativeVar;
351 RelativeVar.dwKind=VAR_LOCAL;
352 RelativeVar.bOffsetOffset=0;
353 RelativeVar.offset=-LocalVar_ThisPtrOffset;
354
355 SetReg_WholeVariable(Type(DEF_PTR_VOID),&RelativeVar,reg);
356}
357
358bool GetVarOffset(bool isErrorEnabled,bool isWriteAccess,const char *NameBuffer,RELATIVE_VAR *pRelativeVar,Type &resultType, Subscripts *pResultSubscripts ){
359 char variable[VN_SIZE];
360
361 if(NameBuffer[0]=='.'){
362 GetWithName(variable);
363 lstrcat(variable,NameBuffer);
364 }
365 else lstrcpy(variable,NameBuffer);
366
367 // 名前空間を分離
368 char namespaceStr[VN_SIZE]="", simpleName[VN_SIZE];
369 compiler.GetObjectModule().meta.GetNamespaces().SplitNamespace( variable, namespaceStr, simpleName );
370
371 // 先頭オブジェクトまたはクラス名と入れ子メンバに分割
372 ReferenceKind refType;
373 char member[VN_SIZE],array[VN_SIZE],lpPtrOffset[VN_SIZE];
374 GetVarFormatString(simpleName,array,lpPtrOffset,member,refType);
375
376 // 名前空間を分離していた場合は結合
377 char VarName[VN_SIZE];
378 if( namespaceStr[0] ){
379 sprintf( VarName, "%s.%s", namespaceStr, simpleName );
380 }
381 else{
382 lstrcpy( VarName, simpleName );
383 }
384
385 const Subscripts *pSubscripts;
386 bool bConst = false;
387
388
389 if( UserProc::IsLocalAreaCompiling() ){
390 //////////////////
391 // ローカル変数
392 //////////////////
393
394 const Variable *pVar = UserProc::CompilingUserProc().GetLocalVars().BackSearch( Symbol( VarName ) );
395 if( pVar ){
396 //ポインタ変数の場合
397 if( pVar->GetType().IsPointer() ){
398 if( !pVar->IsArray() ){
399 lstrcpy(lpPtrOffset,array);
400 array[0]=0;
401 }
402 }
403 else{
404 if(lpPtrOffset[0]){
405 compiler.errorMessenger.Output(16,variable,cp);
406 pRelativeVar->dwKind=NON_VAR;
407 return false;
408 }
409 }
410
411 pRelativeVar->offset=-pVar->GetOffsetAddress();
412 pRelativeVar->bOffsetOffset=0;
413 if( pVar->IsRef() ){
414 // 参照型
415 pRelativeVar->dwKind = VAR_REFLOCAL;
416 }
417 else pRelativeVar->dwKind=VAR_LOCAL;
418 resultType = pVar->GetType();
419 pSubscripts = &pVar->GetSubscripts();
420 bConst = pVar->IsConst();
421
422
423 /////////////////////////////////////////////////////////
424 // ☆★☆ ジェネリクスサポート ☆★☆
425
426 if( resultType.IsTypeParameter() )
427 {
428 // 型パラメータだったとき
429
430 int ptrLevel = PTR_LEVEL( resultType.GetBasicType() );
431
432 // 制約クラス(指定されていないときはObjectクラス)にセットする
433 resultType.SetBasicType( DEF_OBJECT );
434
435 for( int i=0; i<ptrLevel; i++ )
436 {
437 resultType.PtrLevelUp();
438 }
439 }
440
441 //
442 /////////////////////////////////////////////////////////
443
444 goto ok;
445 }
446 }
447
448 if(compiler.pCompilingClass){
449 //////////////////////
450 // クラスメンバの参照
451 //////////////////////
452
453 if(lstrcmpi(variable,"This")==0){
454 //Thisオブジェクト
455
456 //Thisポインタをecxにコピー
457 SetThisPtrToReg(REG_ECX);
458
459 pRelativeVar->dwKind=VAR_DIRECTMEM;
460
461 resultType.SetType( DEF_OBJECT, compiler.pCompilingClass );
462 return true;
463 }
464
465 if(memicmp(variable,"This.",5)==0){
466 //Thisオブジェクトのメンバを参照するとき
467 SlideString(variable+5,-5);
468 lstrcpy(VarName,variable);
469 }
470 else{
471 //クラス内の動的メンバを参照するとき(通常)
472
473 if( !compiler.pCompilingClass->HasDynamicMember( VarName ) )
474 {
475 goto NonClassMember;
476 }
477 }
478
479 //Const修飾子のメソッド内でメンバ書き込みアクセスが発生したとき
480 //(コンストラクタ、デストラクタ内を除く)
481 const CMethod *pMethod = compiler.GetObjectModule().meta.GetClasses().GetNowCompilingMethodInfo();
482 if( isWriteAccess &&
483 pMethod->IsConst() &&
484 compiler.pCompilingClass->IsCompilingConstructor() == false &&
485 compiler.pCompilingClass->IsCompilingDestructor() == false
486 ){
487 compiler.errorMessenger.Output(131, NULL, cp );
488 }
489
490 /////////////////////////////
491 // thisポインタをecxにセット
492
493 //Thisポインタをecxにコピー
494 SetThisPtrToReg(REG_ECX);
495
496 pRelativeVar->dwKind=VAR_DIRECTMEM;
497 if(!_member_offset(
498 isErrorEnabled,
499 isWriteAccess,
500 Type( DEF_OBJECT, *compiler.pCompilingClass ),
501 variable,
502 pRelativeVar,
503 resultType,1)) return false;
504 return true;
505 }
506
507NonClassMember:
508
509 {
510 const Variable *pVar;
511
512 //////////////////////////
513 // 静的ローカル変数
514 // ※"Static.Object.Method.Variable"
515 //////////////////////////
516
517 char temporary[VN_SIZE];
518 if( UserProc::IsLocalAreaCompiling() ){
519 GetNowStaticVarFullName(VarName,temporary);
520
521 pVar = compiler.GetObjectModule().meta.GetGlobalVars().Find( Symbol( temporary ) );
522 if( pVar ){
523 goto GlobalOk;
524 }
525 }
526
527
528 //////////////////////////
529 // クラスの静的メンバ
530 //////////////////////////
531
532 if(member[0]){
533 lstrcpy(temporary,member);
534
535 // TODO: 名前空間を考慮したコードになっていない
536
537 char tempMember[VN_SIZE];
538 char tempArray[VN_SIZE];
539 {
540 ReferenceKind refType;
541 GetVarFormatString(temporary,tempArray,lpPtrOffset,tempMember, refType );
542 }
543
544 int typeDefIndex = compiler.GetObjectModule().meta.GetTypeDefs().GetIndex( VarName );
545 if( typeDefIndex != -1 ){
546 // TypeDef後の型名だったとき
547 lstrcpy( VarName, compiler.GetObjectModule().meta.GetTypeDefs()[typeDefIndex].GetBaseName().c_str() );
548 }
549
550 char temp2[VN_SIZE];
551 sprintf(temp2,"%s.%s",VarName,temporary);
552 pVar = compiler.GetObjectModule().meta.GetGlobalVars().Find( Symbol( temp2 ) );
553 if( pVar ){
554 lstrcpy(member,tempMember);
555 lstrcpy(array,tempArray);
556 goto GlobalOk;
557 }
558 }
559
560 if(compiler.pCompilingClass){
561 //自身のクラスから静的メンバを参照する場合
562 char temp2[VN_SIZE];
563 sprintf(temp2,"%s.%s",compiler.pCompilingClass->GetName().c_str(),VarName);
564 pVar = compiler.GetObjectModule().meta.GetGlobalVars().Find( Symbol( temp2 ) );
565 if( pVar ){
566 goto GlobalOk;
567 }
568 }
569
570 /////////////////////
571 // グローバル変数
572 /////////////////////
573
574 pVar = compiler.GetObjectModule().meta.GetGlobalVars().BackSearch( Symbol( VarName ) );
575 if( pVar ){
576 goto GlobalOk;
577 }
578
579 if(isErrorEnabled) compiler.errorMessenger.Output(3,variable,cp);
580 pRelativeVar->dwKind=NON_VAR;
581 return false;
582
583
584
585GlobalOk:
586 //ポインタ変数の場合
587 if( pVar->GetType().IsPointer() ){
588 if( !pVar->IsArray() ){
589 lstrcpy(lpPtrOffset,array);
590 array[0]=0;
591 }
592 }
593 else{
594 if(lpPtrOffset[0]){
595 compiler.errorMessenger.Output(16,variable,cp);
596 pRelativeVar->dwKind=NON_VAR;
597 return false;
598 }
599 }
600
601 pRelativeVar->offset=pVar->GetOffsetAddress();
602 pRelativeVar->bOffsetOffset=0;
603 if( pVar->IsRef() ){
604 // 参照型
605 pRelativeVar->dwKind = VAR_REFGLOBAL;
606 }
607 else pRelativeVar->dwKind=VAR_GLOBAL;
608 resultType = pVar->GetType();
609 pSubscripts=&pVar->GetSubscripts();
610 bConst = pVar->IsConst();
611 }
612
613
614
615ok:
616
617 if( bConst && isWriteAccess ){
618 //Const定義の変数に書き込みアクセスをしようとした場合
619 if( resultType.IsObject() ){
620 //オブジェクト定数
621 compiler.errorMessenger.Output(130, VarName, cp );
622 }
623 else{
624 //一般のConst変数
625 compiler.errorMessenger.Output(61,VarName,cp);
626 }
627 }
628
629 if( array[0] == 0 && pSubscripts->size() > 0 ){
630 //配列の先頭ポインタを示す場合
631 resultType.SetBasicType( resultType.GetBasicType() | FLAG_PTR );
632
633 if( pResultSubscripts )
634 {
635 (*pResultSubscripts) = *pSubscripts;
636 }
637 return true;
638 }
639
640 if(array[0]||member[0]){
641 //xor ecx,ecx(ecxを0に初期化する)
642 //※ecxは変数ベースアドレスからの相対オフセットを示す
643 compiler.codeGenerator.op_zero_reg(REG_ECX);
644
645 pRelativeVar->bOffsetOffset=1;
646 }
647 if(array[0]){
648 if(!GetArrayOffset(*pSubscripts,array,resultType)){
649 compiler.errorMessenger.Output(14,variable,cp);
650 pRelativeVar->dwKind=NON_VAR;
651 return false;
652 }
653 }
654 if(member[0]){
655 if( resultType.IsObject() || resultType.IsStruct() ){
656 //実態オブジェクトのメンバを参照(obj.member)
657 if( refType != RefDot ){
658 compiler.errorMessenger.Output(104,VarName,cp);
659 pRelativeVar->dwKind=NON_VAR;
660 return false;
661 }
662
663 if( resultType.IsObject() ){
664 // 参照内容へのポインタを抽出
665 SetRelativeOffset( *pRelativeVar );
666 }
667 }
668 else if( resultType.IsObjectPtr() || resultType.IsStructPtr() ){
669 //ポインタオブジェクトが示すメンバを参照
670 if(lpPtrOffset[0]){
671 //pObj[n].member
672 if( refType != RefDot ){
673 compiler.errorMessenger.Output(104,VarName,cp);
674 pRelativeVar->dwKind=NON_VAR;
675 return false;
676 }
677 SetRelativeOffset(resultType,pRelativeVar,lpPtrOffset);
678 pRelativeVar->dwKind=VAR_DIRECTMEM;
679 }
680 else{
681 //pObj->member
682 if( refType != RefPointer ){
683 compiler.errorMessenger.Output(104,VarName,cp);
684 pRelativeVar->dwKind=NON_VAR;
685 return false;
686 }
687
688 SetVarPtrToEax(pRelativeVar);
689 pRelativeVar->dwKind=VAR_DIRECTMEM;
690
691 //mov ecx,dword ptr[eax]
692 compiler.codeGenerator.op_mov_RM( sizeof(long), REG_ECX, REG_EAX, 0, MOD_BASE );
693 }
694 }
695 else if( resultType.GetBasicType()==MAKE_PTR_TYPE(DEF_OBJECT,2) || resultType.GetBasicType()==MAKE_PTR_TYPE(DEF_STRUCT,2)){
696 //ポインタオブジェクトが示すメンバを参照
697 if(lpPtrOffset[0]){
698 //ppObj[n]->member
699 if( refType != RefPointer ){
700 compiler.errorMessenger.Output(104,VarName,cp);
701 pRelativeVar->dwKind=NON_VAR;
702 return false;
703 }
704
705 SetRelativeOffset(resultType,pRelativeVar,lpPtrOffset);
706 pRelativeVar->dwKind=VAR_DIRECTMEM;
707
708
709 SetVarPtrToEax(pRelativeVar);
710
711 //mov ecx,dword ptr[eax]
712 compiler.codeGenerator.op_mov_RM( sizeof(long), REG_ECX, REG_EAX, 0, MOD_BASE );
713 }
714 else{
715 compiler.errorMessenger.Output(104,VarName,cp);
716 pRelativeVar->dwKind=NON_VAR;
717 return false;
718 }
719 }
720 else{
721 compiler.errorMessenger.Output(102,VarName,cp);
722 pRelativeVar->dwKind=NON_VAR;
723 return false;
724 }
725
726 Type classType( resultType );
727
728 if(!_member_offset(
729 isErrorEnabled,
730 isWriteAccess,
731 classType,
732 member,pRelativeVar,resultType,0)) return false;
733
734 return true;
735 }
736
737 if(lpPtrOffset[0]){
738 SetRelativeOffset(resultType,pRelativeVar,lpPtrOffset);
739 pRelativeVar->dwKind=VAR_DIRECTMEM;
740 }
741
742 return true;
743}
744
745bool SetInitGlobalData(int offset,const Type &type,const Subscripts &subscripts,const char *lpszInitBuf){
746 int i2,i3;
747 char temporary[VN_SIZE];
748 char InitBuf[VN_SIZE];
749 lstrcpy( InitBuf, lpszInitBuf );
750
751 if(InitBuf[0]=='['){
752 SlideString(InitBuf+1,-1);
753 InitBuf[lstrlen(InitBuf)-1]=0;
754
755 int typeSize = type.GetSize();
756
757 if( subscripts.size() > 0 ){
758 Subscripts nestSubscripts;
759 for( int i=1; i<(int)subscripts.size(); i++ )
760 {
761 nestSubscripts.push_back( subscripts[i] );
762 }
763
764 typeSize*=JumpSubScripts( nestSubscripts );
765 {
766 int i=0;
767 i2=0;
768 while(1){
769 if( subscripts[0] < i2 ){
770 compiler.errorMessenger.Output(41,0,cp);
771 return 0;
772 }
773 i=GetOneParameter(InitBuf,i,temporary);
774 if(!SetInitGlobalData(
775 offset+i2*typeSize,
776 type,
777 nestSubscripts,
778 temporary)) return false;
779 i2++;
780 if(InitBuf[i]=='\0') break;
781 }
782 }
783 return true;
784 }
785
786 if(type.IsStruct()){
787 const CClass &objClass = type.GetClass();
788
789 int i = 0;
790 BOOST_FOREACH( CMember *pMember, objClass.GetDynamicMembers() ){
791 if(InitBuf[i]=='\0'){
792 compiler.errorMessenger.Output(41,0,cp);
793 return false;
794 }
795
796 i=GetOneParameter(InitBuf,i,temporary);
797
798 i3=objClass.GetMemberOffset( pMember->GetName().c_str() );
799
800 if(!SetInitGlobalData(offset+i3,
801 pMember->GetType(),
802 pMember->GetSubscripts(),
803 temporary)) return false;
804 }
805 return true;
806 }
807
808 compiler.errorMessenger.Output(41,0,cp);
809 return false;
810 }
811
812
813 ///////////////////////////////////////
814 // 単発式([]で囲まれていない)
815 ///////////////////////////////////////
816
817 if( subscripts.size() > 0 ){
818 compiler.errorMessenger.Output(41,0,cp);
819 return false;
820 }
821
822 double dbl;
823 _int64 i64data;
824 Type calcType;
825
826 if( !StaticCalculation(false, InitBuf,type.GetBasicType(),&i64data,calcType) ){
827 //動的データだった場合
828 return false;
829 }
830 if( calcType.IsReal() ){
831 memcpy(&dbl,&i64data,sizeof(double));
832 i64data=(_int64)dbl;
833 }
834 else dbl=(double)i64data;
835
836 //型チェック
837 CheckDifferentType(
838 type,
839 calcType,
840 0,0);
841
842 if( type.IsDouble() ){
843 compiler.GetObjectModule().meta.GetGlobalVars().initAreaBuffer.Overwrite(
844 offset,
845 (const char *)&dbl,
846 sizeof(double)
847 );
848 }
849 else if( type.IsSingle() ){
850 float flt = (float)dbl;
851 compiler.GetObjectModule().meta.GetGlobalVars().initAreaBuffer.Overwrite(
852 offset,
853 (const char *)&flt,
854 sizeof(float)
855 );
856 }
857 else if( type.Is64() ){
858 compiler.GetObjectModule().meta.GetGlobalVars().initAreaBuffer.Overwrite(
859 offset,
860 (const char *)&i64data,
861 sizeof(_int64)
862 );
863 }
864 else if( type.IsLong() || type.IsDWord() || type.IsPointer() ){
865 if( type.GetBasicType() == typeOfPtrChar && calcType.GetIndex() == LITERAL_STRING )
866 {
867 //文字列定数のとき
868
869 char *temp;
870 temp=(char *)i64data;
871 i2=compiler.GetObjectModule().dataTable.AddString(temp,lstrlen(temp));
872 HeapDefaultFree(temp);
873
874 //mov eax,DataPos
875 compiler.codeGenerator.op_mov_RV( REG_EAX, i2, Schedule::DataTable );
876
877 //mov dword ptr[offset],eax
878 compiler.codeGenerator.op_mov_MR( sizeof(long), REG_EAX, 0, offset, MOD_DISP32, Schedule::GlobalVar );
879 }
880 else{
881 long l = (long)i64data;
882 compiler.GetObjectModule().meta.GetGlobalVars().initAreaBuffer.Overwrite(
883 offset,
884 (const char *)&l,
885 sizeof(long)
886 );
887 }
888 }
889 else if( type.IsWord() || type.IsInteger() ){
890 short s = (short)i64data;
891 compiler.GetObjectModule().meta.GetGlobalVars().initAreaBuffer.Overwrite(
892 offset,
893 (const char *)&s,
894 sizeof(short)
895 );
896 }
897 else if( type.IsSByte() || type.IsByte() || type.IsBoolean() ){
898 char c = (char)i64data;
899 compiler.GetObjectModule().meta.GetGlobalVars().initAreaBuffer.Overwrite(
900 offset,
901 (const char *)&c,
902 sizeof(char)
903 );
904 }
905
906 return true;
907}
908bool InitLocalVar(int offset,const Type &type,const Subscripts &subscripts,const char *lpszInitBuf){
909 int i2,i3;
910 char temporary[VN_SIZE];
911 char InitBuf[VN_SIZE];
912 lstrcpy( InitBuf, lpszInitBuf );
913
914 if(InitBuf[0]=='['){
915 SlideString(InitBuf+1,-1);
916 InitBuf[lstrlen(InitBuf)-1]=0;
917
918 int typeSize = type.GetSize();
919
920 if( subscripts.size() > 0 ){
921 Subscripts nestSubscripts;
922 for( int i=1; i<(int)subscripts.size(); i++ )
923 {
924 nestSubscripts.push_back( subscripts[i] );
925 }
926
927 typeSize*=JumpSubScripts( nestSubscripts );
928 {
929 int i=0;
930 i2=0;
931 while(1){
932 if( subscripts[0] < i2 ){
933 compiler.errorMessenger.Output(41,0,cp);
934 return 0;
935 }
936 i=GetOneParameter(InitBuf,i,temporary);
937 if(!InitLocalVar(
938 offset+i2*typeSize,
939 type,
940 nestSubscripts,
941 temporary)) return false;
942 i2++;
943 if(InitBuf[i]=='\0') break;
944 }
945 }
946 return true;
947 }
948
949 if(type.IsStruct()){
950 const CClass &objClass = type.GetClass();
951
952 int i = 0;
953 BOOST_FOREACH( CMember *pMember, objClass.GetDynamicMembers() ){
954 if(InitBuf[i]=='\0'){
955 compiler.errorMessenger.Output(41,0,cp);
956 return false;
957 }
958
959 i=GetOneParameter(InitBuf,i,temporary);
960
961 i3=objClass.GetMemberOffset( pMember->GetName().c_str() );
962
963 if(!InitLocalVar(offset+i3,
964 pMember->GetType(),
965 pMember->GetSubscripts(),
966 temporary)) return false;
967
968 if(InitBuf[i]=='\0') break;
969 }
970 return true;
971 }
972
973 compiler.errorMessenger.Output(41,0,cp);
974 return false;
975 }
976
977
978 ///////////////////////////////////////
979 // 単発式([]で囲まれていない)
980 ///////////////////////////////////////
981
982 if( subscripts.size() > 0 ){
983 compiler.errorMessenger.Output(41,0,cp);
984 return false;
985 }
986
987 double dbl;
988 _int64 i64data;
989 Type calcType;
990
991 if( !StaticCalculation(false, InitBuf,type.GetBasicType(),&i64data,calcType) ){
992 //動的データだった場合
993 return false;
994 }
995 if( calcType.IsReal() ){
996 memcpy(&dbl,&i64data,sizeof(double));
997 i64data=(_int64)dbl;
998 }
999 else dbl=(double)i64data;
1000
1001 //型チェック
1002 CheckDifferentType(
1003 type,
1004 calcType,
1005 0,0);
1006
1007 if( type.IsDouble() ){
1008 //mov eax,HILONG(dbl)
1009 compiler.codeGenerator.op_mov_RV( REG_EAX, *(long *)(((char *)(&dbl))+4) );
1010
1011 //mov dword ptr[ebp+offset+sizeof(long)],eax
1012 compiler.codeGenerator.localVarPertialSchedules.push_back(
1013 compiler.codeGenerator.op_mov_MR( sizeof(long), REG_EAX, REG_EBP, offset+sizeof(long), MOD_BASE_DISP32, Schedule::None, true )
1014 );
1015
1016 //mov eax,LOLONG(dbl)
1017 compiler.codeGenerator.op_mov_RV( REG_EAX, *(long *)(&dbl) );
1018
1019 //mov dword ptr[ebp+offset],eax
1020 compiler.codeGenerator.localVarPertialSchedules.push_back(
1021 compiler.codeGenerator.op_mov_MR( sizeof(long), REG_EAX, REG_EBP, offset, MOD_BASE_DISP32, Schedule::None, true )
1022 );
1023 }
1024 else if( type.IsSingle() ){
1025 float flt;
1026 flt=(float)dbl;
1027
1028 //mov eax,InitValue
1029 compiler.codeGenerator.op_mov_RV( REG_EAX, *(long *)&flt );
1030
1031 //mov dword ptr[ebp+offset],eax
1032 compiler.codeGenerator.localVarPertialSchedules.push_back(
1033 compiler.codeGenerator.op_mov_MR( sizeof(long), REG_EAX, REG_EBP, offset, MOD_BASE_DISP32, Schedule::None, true )
1034 );
1035 }
1036 else if( type.Is64() ){
1037 //mov eax,HILONG(i64data)
1038 compiler.codeGenerator.op_mov_RV( REG_EAX, *(long *)(((char *)(&i64data))+4) );
1039
1040 //mov dword ptr[ebp+offset+sizeof(long)],eax
1041 compiler.codeGenerator.localVarPertialSchedules.push_back(
1042 compiler.codeGenerator.op_mov_MR( sizeof(long), REG_EAX, REG_EBP, offset+sizeof(long), MOD_BASE_DISP32, Schedule::None, true )
1043 );
1044
1045 //mov eax,LOLONG(i64data)
1046 compiler.codeGenerator.op_mov_RV( REG_EAX, *(long *)(&i64data) );
1047
1048 //mov dword ptr[ebp+offset],eax
1049 compiler.codeGenerator.localVarPertialSchedules.push_back(
1050 compiler.codeGenerator.op_mov_MR( sizeof(long), REG_EAX, REG_EBP, offset, MOD_BASE_DISP32, Schedule::None, true )
1051 );
1052 }
1053 else if( type.IsDWord() || type.IsLong() || type.IsPointer() ){
1054 if( type.GetBasicType() == typeOfPtrChar && calcType.GetIndex() == LITERAL_STRING )
1055 {
1056 //文字列定数のとき
1057
1058 char *temp;
1059 temp=(char *)i64data;
1060 i2=compiler.GetObjectModule().dataTable.AddString(temp,lstrlen(temp));
1061 HeapDefaultFree(temp);
1062
1063 //mov eax,DataPos
1064 compiler.codeGenerator.op_mov_RV( REG_EAX, i2, Schedule::DataTable );
1065 }
1066 else{
1067 //mov eax,InitValue
1068 compiler.codeGenerator.op_mov_RV( REG_EAX, (long)i64data );
1069 }
1070
1071 //mov dword ptr[ebp+offset],eax
1072 compiler.codeGenerator.localVarPertialSchedules.push_back(
1073 compiler.codeGenerator.op_mov_MR( sizeof(long), REG_EAX, REG_EBP, offset, MOD_BASE_DISP32, Schedule::None, true )
1074 );
1075 }
1076 else if( type.IsWord() || type.IsInteger() ){
1077 //mov word ptr[ebp+offset],InitValue
1078 compiler.codeGenerator.localVarPertialSchedules.push_back(
1079 compiler.codeGenerator.op_mov_MV( sizeof(short), REG_EBP, offset, Schedule::None, true, (long)i64data )
1080 );
1081 }
1082 else if( type.IsSByte() || type.IsByte() || type.IsBoolean() ){
1083 //mov byte ptr[ebp+offset],InitValue
1084 compiler.codeGenerator.localVarPertialSchedules.push_back(
1085 compiler.codeGenerator.op_mov_MV( sizeof(char), REG_EBP, offset, Schedule::None, true, (long)i64data )
1086 );
1087 }
1088
1089 return true;
1090}
1091
1092void dim( char *VarName, const Subscripts &subscripts, const Type &type,const char *InitBuf,const char *ConstractParameter,DWORD dwFlags){
1093 if( UserProc::IsGlobalAreaCompiling() ){
1094 /////////////////////////
1095 // グローバル変数
1096 /////////////////////////
1097
1098 AddGlobalVariable(VarName,subscripts,type,InitBuf,ConstractParameter,dwFlags);
1099 }
1100 else{
1101 /////////////////
1102 // ローカル変数
1103 /////////////////
1104
1105 if( UserProc::CompilingUserProc().GetLocalVars().DuplicateCheck( Symbol( VarName ) ) ){
1106 //2重定義のエラー
1107 compiler.errorMessenger.Output(15,VarName,cp);
1108 return;
1109 }
1110
1111 bool isConst = ( dwFlags & DIMFLAG_CONST ) ? true:false;
1112
1113 Variable *pVar = new Variable( VarName, type, isConst, false, ConstractParameter, false );
1114
1115 if( subscripts.size() > 0 ){
1116 //配列あり
1117 pVar->SetArray( subscripts );
1118 }
1119
1120 //レキシカルスコープ
1121 pVar->SetScopeLevel( compiler.codeGenerator.lexicalScopes.GetNowLevel() );
1122 pVar->SetScopeStartAddress( compiler.codeGenerator.lexicalScopes.GetStartAddress() );
1123 pVar->isLiving = true;
1124
1125 //エラー用
1126 pVar->source_code_address=cp;
1127
1128 // 変数を追加
1129 UserProc::CompilingUserProc().GetLocalVars().push_back( pVar );
1130
1131 //アラインメントを考慮
1132 if( pVar->GetType().IsStruct() ){
1133 int alignment = pVar->GetType().GetClass().GetFixedAlignment();
1134
1135 if( alignment ){
1136 if( AllLocalVarSize % alignment ){
1137 AllLocalVarSize += alignment - (AllLocalVarSize % alignment);
1138 }
1139 }
1140
1141 if( alignment == PTR_SIZE*2 ){
1142 // ポインタに要するサイズよりも一回り大きなアラインメントが指定されているとき
1143 // (例:CONTEXT構造体など)
1144 // 呼び出し側のオフセットズレを考慮する
1145
1146 if( 0 == ( UserProc::CompilingUserProc().RealParams().GetMemorySize() + PTR_SIZE /* ret分 */ ) % alignment ){
1147 AllLocalVarSize += PTR_SIZE;
1148 }
1149 }
1150 }
1151
1152 AllLocalVarSize += pVar->GetMemorySize();
1153 pVar->SetOffsetAddress( AllLocalVarSize );
1154
1155 //レキシカルスコープ
1156 pVar->SetScopeLevel( compiler.codeGenerator.lexicalScopes.GetNowLevel() );
1157 pVar->SetScopeStartAddress( compiler.codeGenerator.lexicalScopes.GetStartAddress() );
1158 pVar->isLiving = true;
1159
1160 if(InitBuf[0]){
1161 //初期代入時のみ、書き込みアクセスを許可する
1162 if( isConst ){
1163 pVar->ConstOff();
1164 }
1165
1166 int result = 0;
1167 if( !pVar->GetType().IsObject() ){
1168 result = InitLocalVar(-pVar->GetOffsetAddress(),
1169 pVar->GetType(),
1170 pVar->GetSubscripts(),
1171 InitBuf);
1172 }
1173
1174 if(!result){
1175 //動的な式だった場合は代入演算を行う
1176 char temporary[8192];
1177 sprintf(temporary,"%s=%s",VarName,InitBuf);
1178 OpcodeCalc(temporary);
1179 }
1180
1181 if( isConst ){
1182 pVar->ConstOn();
1183 }
1184 }
1185 else{
1186 //push 0
1187 compiler.codeGenerator.op_push_V(0);
1188
1189 //push VarSize
1190 compiler.codeGenerator.op_push_V( pVar->GetMemorySize() );
1191
1192 //mov eax,ebp
1193 compiler.codeGenerator.op_mov_RR( REG_EAX, REG_EBP );
1194
1195 //add eax,offset
1196 compiler.codeGenerator.localVarPertialSchedules.push_back(
1197 compiler.codeGenerator.op_add_RV( REG_EAX, -pVar->GetOffsetAddress(), Schedule::None, true )
1198 );
1199
1200 //push eax
1201 compiler.codeGenerator.op_push(REG_EAX);
1202
1203 //call FillMemory
1204 compiler.codeGenerator.op_call( GetDeclareHash("FillMemory") );
1205 }
1206 }
1207
1208 //New呼び出し
1209 if( type.IsObject()
1210 && !type.IsInterface() && !type.IsComInterface()
1211 &&(dwFlags&DIMFLAG_NONCALL_CONSTRACTOR)==0
1212 &&InitBuf[0]=='\0')
1213 {
1214 char objectSize[255];
1215 if( subscripts.size() == 0 ){
1216 objectSize[0] = 0;
1217 }
1218 else{
1219 if( subscripts.size() > 1 ){
1220 compiler.errorMessenger.Output(300,NULL,cp);
1221 }
1222 sprintf( objectSize, "%d", subscripts[0] );
1223 }
1224 Operator_New( type.GetClass(), objectSize, ConstractParameter, type );
1225
1226 //pop eax
1227 compiler.codeGenerator.op_pop( REG_EAX );
1228
1229 RELATIVE_VAR RelativeVar;
1230 GetVarOffset( true, false, VarName, &RelativeVar, Type() );
1231 if( RelativeVar.dwKind == VAR_DIRECTMEM ){
1232 compiler.errorMessenger.OutputFatalError();
1233 }
1234 SetVariableFromEax( Type( DEF_OBJECT, *compiler.GetObjectModule().meta.GetClasses().GetObjectClassPtr() ), DEF_OBJECT, &RelativeVar );
1235 }
1236}
1237
1238void SetVarPtrToEax(RELATIVE_VAR *pRelativeVar){
1239 if(pRelativeVar->dwKind==VAR_GLOBAL){
1240 if(pRelativeVar->bOffsetOffset){
1241 //lea eax,dword ptr[ecx+offset]
1242 compiler.codeGenerator.op_lea_RM( REG_EAX, REG_ECX, pRelativeVar->offset, MOD_BASE_DISP32, Schedule::GlobalVar );
1243 }
1244 else{
1245 //mov eax,offset
1246 compiler.codeGenerator.op_mov_RV( REG_EAX, pRelativeVar->offset, Schedule::GlobalVar );
1247 }
1248 }
1249 else if(pRelativeVar->dwKind==VAR_REFGLOBAL){
1250 if(pRelativeVar->bOffsetOffset){
1251 //mov eax,ecx
1252 compiler.codeGenerator.op_mov_RR( REG_EAX, REG_ECX );
1253
1254 //add eax,dword ptr[offset]
1255 compiler.codeGenerator.op_add_RM( sizeof(long), REG_EAX, REG_NON, (int)pRelativeVar->offset, MOD_DISP32, Schedule::GlobalVar );
1256 }
1257 else{
1258 //mov eax,dword ptr[offset]
1259 compiler.codeGenerator.op_mov_RM( sizeof(long), REG_EAX, REG_NON, (int)pRelativeVar->offset, MOD_DISP32, Schedule::GlobalVar );
1260 }
1261 }
1262 else if(pRelativeVar->dwKind==VAR_LOCAL){
1263 if(pRelativeVar->bOffsetOffset){
1264 //add ecx,offset
1265 compiler.codeGenerator.localVarPertialSchedules.push_back(
1266 compiler.codeGenerator.op_add_RV( REG_ECX, pRelativeVar->offset, Schedule::None, true )
1267 );
1268
1269 //lea eax,dword ptr[ebp+ecx]
1270 compiler.codeGenerator.PutOld(
1271 (char)0x8D,
1272 (char)0x44,
1273 (char)0x0D,
1274 (char)0x00
1275 );
1276 }
1277 else{
1278 //lea eax,dword ptr[ecx+offset]
1279 compiler.codeGenerator.localVarPertialSchedules.push_back(
1280 compiler.codeGenerator.op_lea_RM( REG_EAX, REG_EBP, pRelativeVar->offset, MOD_BASE_DISP32, Schedule::None, true )
1281 );
1282 }
1283 }
1284 else if(pRelativeVar->dwKind==VAR_REFLOCAL){
1285 if(pRelativeVar->bOffsetOffset){
1286 //mov eax,ecx
1287 compiler.codeGenerator.op_mov_RR( REG_EAX, REG_ECX );
1288
1289 //add eax,dword ptr[ebp+offset]
1290 compiler.codeGenerator.localVarPertialSchedules.push_back(
1291 compiler.codeGenerator.op_add_RM( sizeof(long), REG_EAX, REG_EBP, pRelativeVar->offset, MOD_BASE_DISP32, Schedule::None, true )
1292 );
1293 }
1294 else{
1295 //mov eax,dword ptr[ebp+offset]
1296 compiler.codeGenerator.localVarPertialSchedules.push_back(
1297 compiler.codeGenerator.op_mov_RM( sizeof(long), REG_EAX, REG_EBP, pRelativeVar->offset, MOD_BASE_DISP32, Schedule::None, true )
1298 );
1299 }
1300 }
1301 else if(pRelativeVar->dwKind==VAR_DIRECTMEM){
1302 //mov eax,ecx
1303 compiler.codeGenerator.op_mov_RR( REG_EAX, REG_ECX );
1304 }
1305}
1306void SetVarPtrToReg(int reg,RELATIVE_VAR *pRelativeVar){
1307 if( reg != REG_EAX ){
1308 compiler.errorMessenger.OutputFatalError();
1309 //TODO: 未完成
1310 }
1311 SetVarPtrToEax( pRelativeVar );
1312}
1313
1314bool Compile_AddGlobalRootsForGc(){
1315 const UserProc *pUserProc_AddGlobalRootPtr = GetClassMethod( "_System_CGarbageCollection", "AddGlobalRootPtr" );
1316 if( !pUserProc_AddGlobalRootPtr ){
1317 compiler.errorMessenger.Output(3, "_System_CGarbageCollection.AddGlobalRootPtr", -1 );
1318 return false;
1319 }
1320
1321 BOOST_FOREACH( const Variable *pVar, compiler.GetObjectModule().meta.GetGlobalVars() ){
1322 if( pVar->GetType().IsObject() || pVar->GetType().IsPointer() || pVar->GetType().IsStruct() ){
1323 // オブジェクトまたはポインタだったとき
1324 // ※構造体も含む(暫定対応)
1325
1326 // 変数領域に要するLONG_PTR単位の個数を引き渡す
1327 compiler.codeGenerator.op_push_V( pVar->GetMemorySize()/PTR_SIZE );
1328
1329
1330 /////////////////////////////
1331 // ルートポインタを引き渡す
1332
1333 //mov eax,offset
1334 compiler.codeGenerator.op_mov_RV(REG_EAX,(int)pVar->GetOffsetAddress(), Schedule::GlobalVar );
1335
1336 //push eax
1337 compiler.codeGenerator.op_push( REG_EAX );
1338
1339 //
1340 /////////////////////////////
1341
1342
1343 /////////////////////////////
1344 // Thisポインタを引き渡す
1345
1346 SetThisPtrToReg(REG_EAX);
1347
1348 //push eax
1349 compiler.codeGenerator.op_push( REG_EAX );
1350
1351 //
1352 /////////////////////////////
1353
1354
1355 // call AddGlobalRootPtr
1356 compiler.codeGenerator.op_call( pUserProc_AddGlobalRootPtr );
1357 }
1358 }
1359
1360 return true;
1361}
Note: See TracBrowser for help on using the repository browser.