source: dev/BasicCompiler_Common/Class.cpp@ 89

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

実行時型情報の生成に対応。
関数の戻り値の型に抽象クラスを指定できるようにした。

File size: 34.4 KB
Line 
1#include "common.h"
2
3#ifdef _AMD64_
4#include "../BasicCompiler64/opcode.h"
5#else
6#include "../BasicCompiler32/opcode.h"
7#endif
8
9CDBClass *pobj_DBClass;
10
11CClass *pobj_CompilingClass;
12CClass *pobj_StringClass;
13
14CMember *pCompilingMethod;
15
16
17
18CMember::CMember( CClass *pobj_c, DWORD access, bool isConst, bool isRef, char *buffer, int nowLine ){
19 extern int cp;
20
21 //構文を解析
22 char VarName[VN_SIZE];
23 char init_buf[VN_SIZE];
24 char constract_parameter[VN_SIZE];
25 GetDimentionFormat(buffer,VarName,SubScripts,*this,init_buf,constract_parameter);
26
27 //重複チェック
28 if(pobj_c->DupliCheckAll(VarName)){
29 SetError(15,VarName,cp);
30 }
31
32 /*
33 TODO: 消す
34 メンバ定義は抽象クラスでもOK
35 if( IsObject() ){
36 if( GetClass().IsAbstract() ){
37 //抽象クラスだったとき
38 SetError(125,GetClass().name,cp);
39 }
40 }*/
41
42 //メンバ名
43 name=(char *)HeapAlloc(hHeap,0,lstrlen(VarName)+1);
44 lstrcpy(name,VarName);
45
46 //アクセス権
47 dwAccess=access;
48
49 //定数扱いかどうか
50 this->isConst = isConst;
51
52 //初期データ
53 InitBuf=(char *)HeapAlloc(hHeap,0,lstrlen(init_buf)+1);
54 lstrcpy(InitBuf,init_buf);
55
56 //コンストラクタ用のパラメータ
57 ConstractParameter=(char *)HeapAlloc(hHeap,0,lstrlen(constract_parameter)+1);
58 lstrcpy(ConstractParameter,constract_parameter);
59
60 //ソースコードの位置
61 source_code_address=nowLine;
62}
63CMember::CMember(CMember &member):
64 Type( member )
65{
66
67 //name
68 name=(char *)HeapAlloc(hHeap,0,lstrlen(member.name)+1);
69 lstrcpy(name,member.name);
70
71 //定数扱いかどうか
72 isConst = member.isConst;
73
74 //SubScripts
75 memcpy(SubScripts,member.SubScripts,MAX_ARRAYDIM*sizeof(int));
76
77 //ソースコードの位置
78 source_code_address=member.source_code_address;
79}
80CMember::CMember(){
81 memset(this,0,sizeof(CMember));
82}
83CMember::~CMember(){
84 HeapDefaultFree(name);
85 if(InitBuf) HeapDefaultFree(InitBuf);
86 if(ConstractParameter) HeapDefaultFree(ConstractParameter);
87}
88
89bool CMember::IsConst(){
90 return isConst;
91}
92
93void CMember::InitStaticMember(void){
94 //静的メンバをグローバル領域に作成
95
96 //イテレータをリセット
97 extern CDBClass *pobj_DBClass;
98 pobj_DBClass->Iterator_Reset();
99
100 int back_cp=cp;
101
102 while(pobj_DBClass->Iterator_HasNext()){
103 CClass *pobj_c;
104 pobj_c=pobj_DBClass->Iterator_GetNext();
105
106 int i=0;
107 foreach( CMember *member, pobj_c->staticMembers ){
108 char temporary[VN_SIZE];
109 sprintf(temporary,"%s.%s",pobj_c->name,member->name);
110 dim(
111 temporary,
112 member->SubScripts,
113 *member,
114 member->InitBuf,
115 member->ConstractParameter,
116 0);
117
118 //ネイティブコードバッファの再確保
119 ReallocNativeCodeBuffer();
120
121 i++;
122 }
123 }
124
125 cp=back_cp;
126}
127
128
129
130CMethod::CMethod(CMethod *pobj){
131 //コピーコンストラクタ
132 memset(this,0,sizeof(CMethod));
133
134 pUserProc=pobj->pUserProc;
135
136 bAbstract=pobj->bAbstract;
137
138 bVirtual=pobj->bVirtual;
139}
140CMethod::CMethod(){
141 memset(this,0,sizeof(CMethod));
142}
143CMethod::~CMethod(){
144}
145
146
147
148
149CClass::CClass(const char *name){
150 memset(this,0,sizeof(CClass));
151
152 vtbl_offset=-1;
153
154 this->name=(char *)HeapAlloc(hHeap,0,lstrlen(name)+1);
155 lstrcpy(this->name,name);
156
157 isCompilingConstructor = false;
158 isCompilingDestructor = false;
159}
160CClass::~CClass(){
161 int i;
162
163 //クラス名
164 HeapDefaultFree(name);
165
166 if(ppobj_Member){
167 //メンバ
168 for(i=0;i<iMemberNum;i++){
169 delete ppobj_Member[i];
170 }
171 HeapDefaultFree(ppobj_Member);
172 ppobj_Member=0;
173 }
174
175 //静的メンバ
176 foreach( CMember *member, staticMembers ){
177 delete member;
178 }
179
180 //メソッド
181 foreach( CMethod *method, methods ){
182 delete method;
183 }
184
185 //静的メソッド
186 foreach( CMethod *method, staticMethods ){
187 delete method;
188 }
189}
190
191bool CClass::IsStructure() const
192{
193 return classType == CClass::Structure;
194}
195
196void CClass::Inherits( CClass *pInheritsClass ){
197
198 //メンバをコピー
199 ppobj_Member=(CMember **)HeapReAlloc(
200 hHeap,
201 0,
202 ppobj_Member,
203 pInheritsClass->iMemberNum*sizeof(CMember *));
204 iMemberNum=pInheritsClass->iMemberNum;
205 for(int i3=0;i3<pInheritsClass->iMemberNum;i3++){
206 ppobj_Member[i3]=new CMember( *pInheritsClass->ppobj_Member[i3] );
207
208 //dwAccess
209 if(pInheritsClass->ppobj_Member[i3]->dwAccess==ACCESS_PRIVATE)
210 ppobj_Member[i3]->dwAccess=ACCESS_NON;
211 else ppobj_Member[i3]->dwAccess=pInheritsClass->ppobj_Member[i3]->dwAccess;
212 }
213
214 //メソッドをコピー
215 foreach( CMethod *baseMethod, pInheritsClass->methods ){
216 CMethod *method = new CMethod( baseMethod );
217
218 //dwAccess
219 if(baseMethod->dwAccess==ACCESS_PRIVATE)
220 method->dwAccess=ACCESS_NON;
221 else method->dwAccess=baseMethod->dwAccess;
222
223 //pobj_Inherits
224 // ※継承元のClassIndexをセット(入れ子継承を考慮する)
225 if(baseMethod->pobj_InheritsClass==0)
226 method->pobj_InheritsClass=pInheritsClass;
227 else
228 method->pobj_InheritsClass=
229 baseMethod->pobj_InheritsClass;
230
231 methods.push_back( method );
232 }
233
234 //仮想関数の数
235 vtbl_num=pInheritsClass->vtbl_num;
236
237 //継承先のクラスをメンバとして保持する
238 pobj_InheritsClass = pInheritsClass;
239}
240void CClass::AddMember( DWORD dwAccess, bool isConst, bool isRef, char *buffer ){
241 ppobj_Member = (CMember **)HeapReAlloc( hHeap, 0, ppobj_Member, ( iMemberNum + 1 ) * sizeof(CMember *) );
242 ppobj_Member[iMemberNum] = new CMember( this, dwAccess, isConst, isRef, buffer );
243 iMemberNum++;
244}
245void CClass::AddStaticMember( DWORD dwAccess, bool isConst, bool isRef, char *buffer, int nowLine ){
246 CMember *member = new CMember( this, dwAccess, isConst, isRef, buffer, nowLine );
247 staticMembers.push_back( member );
248}
249void CClass::AddMethod( UserProc *pUserProc,DWORD dwAccess, bool isConst, BOOL bAbstract, BOOL bVirtual ){
250 CMethod *method = new CMethod();
251 method->pUserProc = pUserProc;
252 method->dwAccess = dwAccess;
253 method->isConst = isConst;
254 method->bAbstract = bAbstract;
255 method->bVirtual = bVirtual;
256 method->pobj_InheritsClass = 0;
257
258 methods.push_back( method );
259
260 // プロシージャオブジェクトと関連付け
261 pUserProc->SetMethod( method );
262}
263void CClass::AddStaticMethod(UserProc *pUserProc,DWORD dwAccess){
264 CMethod *method = new CMethod();
265 method->pUserProc=pUserProc;
266 method->dwAccess=dwAccess;
267 method->bAbstract=0;
268 method->bVirtual=0;
269 method->pobj_InheritsClass=0;
270
271 staticMethods.push_back( method );
272
273 // プロシージャオブジェクトと関連付け
274 pUserProc->SetMethod( method );
275}
276BOOL CClass::DupliCheckAll(const char *name){
277 //重複チェック
278
279 //メンバ
280 if(DupliCheckMember(name)) return 1;
281
282 //メソッド
283 foreach( CMethod *method, methods ){
284 if( lstrcmp( name, method->pUserProc->GetName().c_str() ) == 0 ){
285 return 1;
286 }
287 }
288
289 return 0;
290}
291BOOL CClass::DupliCheckMember(const char *name){
292 //重複チェック
293
294 //メンバ
295 for( int i=0;i<iMemberNum;i++){
296 if(lstrcmp(name,ppobj_Member[i]->name)==0){
297 return 1;
298 }
299 }
300
301 //静的メンバ
302 foreach( CMember *member, staticMembers ){
303 if( lstrcmp( name, member->name ) == 0 ){
304 return 1;
305 }
306 }
307
308 return 0;
309}
310CMethod *CClass::GetMethodInfo( UserProc *pUserProc ) const
311{
312 for( int i=(int)methods.size()-1; i>=0; i-- ){
313 if( pUserProc == methods[i]->pUserProc ){
314 return methods[i];
315 }
316 }
317 return NULL;
318}
319CMethod *CClass::GetStaticMethodInfo( UserProc *pUserProc ) const
320{
321 for( int i=(int)staticMethods.size()-1; i>=0; i-- ){
322 if( pUserProc == staticMethods[i]->pUserProc ) return staticMethods[i];
323 }
324 return NULL;
325}
326bool CClass::IsExistMethod( const char *name ) const
327{
328 foreach( CMethod *method, methods ){
329 if( method->pUserProc->GetName() == name ) return true;
330 }
331 return false;
332}
333bool CClass::IsExistStaticMethod( const char *name ) const
334{
335 foreach( CMethod *method, staticMethods ){
336 if( method->pUserProc->GetName() == name ) return true;
337 }
338 return false;
339}
340
341void CClass::EnumStaticMethod( const char *methodName, std::vector<UserProc *> &subs ) const
342{
343 foreach( CMethod *method, staticMethods ){
344 if( method->pUserProc->GetName() == methodName ){
345 subs.push_back( method->pUserProc );
346 }
347 }
348}
349
350void CClass::EnumMethod( const char *methodName, std::vector<UserProc *> &subs ) const
351{
352 //オブジェクトのメンバ関数の場合
353 //※オーバーライドされた関数を先にサーチする必要があるため、バックサーチを行う
354 for( int i=(int)methods.size()-1; i>=0; i-- ){
355 if( methods[i]->pUserProc->GetName() == methodName ){
356 subs.push_back( methods[i]->pUserProc );
357 }
358 }
359}
360
361void CClass::EnumMethod( const BYTE idOperatorCalc, std::vector<UserProc *> &subs ) const
362{
363 //オブジェクトのメンバ関数の場合
364 //※オーバーライドされた関数を先にサーチする必要があるため、バックサーチを行う
365 for( int i=(int)methods.size()-1; i>=0; i-- ){
366 UserProc *pUserProc = methods[i]->pUserProc;
367 const char *temp = pUserProc->GetName().c_str();
368 if(temp[0]==1&&temp[1]==ESC_OPERATOR){
369 if((BYTE)temp[2]==idOperatorCalc){
370 subs.push_back( pUserProc );
371 }
372 }
373 }
374}
375
376//デフォルト コンストラクタ メソッドを取得
377CMethod *CClass::GetConstructorMethod() const
378{
379 if( ConstructorMemberSubIndex == -1 ) return NULL;
380 return methods[ConstructorMemberSubIndex];
381}
382
383//デストラクタ メソッドを取得
384CMethod *CClass::GetDestructorMethod() const
385{
386 if( DestructorMemberSubIndex == -1 ) return NULL;
387 return methods[DestructorMemberSubIndex];
388}
389
390//サイズを取得
391int CClass::GetSize() const
392{
393 return GetMemberOffset( NULL, NULL );
394}
395
396//メンバのオフセットを取得
397int CClass::GetMemberOffset( const char *memberName, int *pMemberNum ) const
398{
399 int i,i2,offset;
400
401 //仮想関数が存在する場合は関数リストへのポインタのサイズを追加
402 if(vtbl_num) offset=PTR_SIZE;
403 else offset=0;
404
405 int alignment;
406 if(iAlign) alignment=iAlign;
407 else alignment=1;
408
409 int iMaxAlign=0;
410 for(i=0;i<iMemberNum;i++){
411 CMember *pMember = ppobj_Member[i];
412
413 i2 = pMember->GetSize();
414
415 //アラインメントを算出
416 int member_size;
417 if( pMember->IsStruct() ){
418 //メンバクラスのアラインメントを取得
419 member_size=pMember->GetClass().GetAlignment();
420 }
421 else{
422 //メンバサイズを取得
423 member_size=i2;
424 }
425 if(iMaxAlign<member_size) iMaxAlign=member_size;
426
427 //アラインメントを考慮
428 if(iAlign&&iAlign<member_size){
429 if(offset%alignment) offset+=alignment-(offset%alignment);
430 }
431 else{
432 if(alignment<member_size) alignment=member_size;
433
434 if(member_size==0){
435 //メンバを持たないクラス
436 //※何もしない(オフセットの計算をしない)
437 }
438 else{
439 if(offset%member_size) offset+=member_size-(offset%member_size);
440 }
441 }
442
443 if(memberName){
444 //メンバ指定がある場合は、オフセットを返す
445 if(lstrcmp(pMember->name,memberName)==0){
446 if(pMemberNum) *pMemberNum=i;
447 return offset;
448 }
449 }
450
451 //配列を考慮したメンバサイズを取得
452 member_size=i2 * JumpSubScripts(pMember->SubScripts);
453
454 //メンバサイズを加算
455 offset+= member_size;
456 }
457
458 if(iMaxAlign<alignment) alignment=iMaxAlign;
459
460 //アラインメントを考慮
461 if(alignment){
462 if(offset%alignment) offset+=alignment-(offset%alignment);
463 }
464
465 if(pMemberNum) *pMemberNum=i;
466 return offset;
467}
468
469int CClass::GetAlignment() const
470{
471 int i;
472 int alignment,member_size;
473
474 if(vtbl_num) alignment=PTR_SIZE;
475 else alignment=0;
476
477 for(i=0;i<iMemberNum;i++){
478 CMember *pMember = ppobj_Member[i];
479
480 if(pMember->IsStruct()){
481 //メンバクラスのアラインメントを取得
482 member_size=pMember->GetClass().GetAlignment();
483 }
484 else{
485 //メンバサイズを取得
486 member_size = pMember->GetSize();
487 }
488
489 //アラインメントをセット
490 if(alignment<member_size) alignment=member_size;
491 }
492
493 if(alignment==0) return 0;
494
495 if(iAlign) alignment=iAlign;
496
497 return alignment;
498}
499
500
501
502int CClass::GetFuncNumInVtbl( const UserProc *pUserProc ) const
503{
504 int n = 0;
505 foreach( CMethod *method, methods ){
506 if( method->pUserProc == pUserProc ) break;
507 if( method->bVirtual ) n++;
508 }
509 return n;
510}
511LONG_PTR CClass::GetVtblGlobalOffset(void){
512
513 //既に存在する場合はそれを返す
514 if(vtbl_offset!=-1) return vtbl_offset;
515
516
517 //////////////////////////////////////
518 // 存在しないときは新たに生成する
519 //////////////////////////////////////
520
521 UserProc **ppsi;
522 ppsi=(UserProc **)HeapAlloc(hHeap,0,vtbl_num*sizeof(UserProc *));
523
524 //関数テーブルに値をセット
525 int i2 = 0;
526 foreach( CMethod *method, methods ){
527 if(method->bVirtual){
528 method->pUserProc->Using();
529
530 if(method->bAbstract){
531 extern int cp;
532 SetError(300,NULL,cp);
533
534 ppsi[i2]=0;
535 }
536 else ppsi[i2]=method->pUserProc;
537 i2++;
538 }
539 }
540
541 vtbl_offset=dataTable.AddBinary((void *)ppsi,vtbl_num*sizeof(LONG_PTR));
542
543 for( int i=0; i < vtbl_num; i++ ){
544 pobj_Reloc->AddSchedule_DataSection(vtbl_offset+i*sizeof(LONG_PTR));
545 }
546
547 HeapDefaultFree(ppsi);
548
549 return vtbl_offset;
550}
551void CClass::ActionVtblSchedule(LONG_PTR ImageBase, LONG_PTR MemPos_CodeSection){
552 if(vtbl_offset==-1) return;
553
554 LONG_PTR *pVtbl;
555 pVtbl=(LONG_PTR *)((char *)dataTable.GetPtr()+vtbl_offset);
556
557 int i;
558 for(i=0;i<vtbl_num;i++){
559 UserProc *pUserProc;
560 pUserProc=(UserProc *)pVtbl[i];
561 if(!pUserProc) continue;
562 pVtbl[i]=pUserProc->beginOpAddress+ImageBase+MemPos_CodeSection;
563 }
564}
565bool CClass::IsAbstract() const
566{
567 //未実装の仮想関数を持つ場合はtrueを返す
568
569 foreach( CMethod *method, methods ){
570 if(method->bVirtual){
571 if(method->bAbstract){
572 return true;
573 }
574 }
575 }
576
577 /*
578 TODO: 消す
579 これはAB5からは良くなった(参照型になったため)
580
581 //コンポジションの関係にあるメンバも検査する
582 for(int i=0;i < iMemberNum;i++){
583 if(ppobj_Member[i]->IsObject()){
584 if(ppobj_Member[i]->GetClass().IsAbstract())
585 return true;
586 }
587 }
588 */
589
590 return false;
591}
592
593// コンストラクタのコンパイルを開始
594void CClass::NotifyStartConstructorCompile(){
595 isCompilingConstructor = true;
596}
597
598//コンストラクタのコンパイルを終了
599void CClass::NotifyFinishConstructorCompile(){
600 isCompilingConstructor = false;
601}
602
603//コンストラクタをコンパイル中かどうかを判別
604bool CClass::IsCompilingConstructor() const
605{
606 return isCompilingConstructor;
607}
608
609//デストラクタのコンパイルを開始
610void CClass::NotifyStartDestructorCompile(){
611 isCompilingDestructor = true;
612}
613
614//デストラクタのコンパイルを終了
615void CClass::NotifyFinishDestructorCompile(){
616 isCompilingDestructor = false;
617}
618
619//デストラクタをコンパイル中かどうかを判別
620bool CClass::IsCompilingDestructor() const
621{
622 return isCompilingDestructor;
623}
624
625
626//自身と等しいクラスかどうかを確認
627bool CClass::IsEquals( const CClass *pClass ) const
628{
629 if( this == pClass ) return true;
630 return false;
631}
632
633//自身の派生クラスかどうかを確認
634bool CClass::IsSubClass( const CClass *pClass ) const
635{
636 pClass = pClass->pobj_InheritsClass;
637 while( pClass ){
638 if( this == pClass ) return true;
639 pClass = pClass->pobj_InheritsClass;
640 }
641 return false;
642}
643
644//自身と等しいまたは派生クラスかどうかを確認
645bool CClass::IsEqualsOrSubClass( const CClass *pClass ) const
646{
647 if( IsEquals( pClass ) ) return true;
648 return IsSubClass( pClass );
649}
650
651
652
653int CDBClass::hash(const char *name){
654 int key;
655
656 for(key=0;*name!='\0';name++){
657 key=((key<<8)+ *name )%MAX_CLASS_HASH;
658 }
659
660 return key;
661}
662
663void CDBClass::DestroyClass(CClass *pobj_c){
664 if(pobj_c->pobj_NextClass){
665 DestroyClass(pobj_c->pobj_NextClass);
666 }
667
668 delete pobj_c;
669}
670
671CDBClass::CDBClass():
672 pStringClass( NULL ),
673 pObjectClass( NULL ),
674 pCompilingClass( NULL ),
675 pCompilingMethod( NULL ),
676 ppobj_IteClass( NULL ),
677 iIteMaxNum( 0 ),
678 iIteNextNum( 0 )
679{
680 memset( pobj_ClassHash, 0, MAX_CLASS_HASH * sizeof(CClass *) );
681}
682CDBClass::~CDBClass(){
683 int i;
684 for(i=0;i<MAX_CLASS_HASH;i++){
685 if(pobj_ClassHash[i]) DestroyClass(pobj_ClassHash[i]);
686 }
687
688 if(ppobj_IteClass) HeapDefaultFree(ppobj_IteClass);
689}
690
691void CDBClass::ActionVtblSchedule(LONG_PTR ImageBase, LONG_PTR MemPos_CodeSection){
692 int i;
693 for(i=0;i<MAX_CLASS_HASH;i++){
694 if(pobj_ClassHash[i]){
695 CClass *pobj_c;
696 pobj_c=pobj_ClassHash[i];
697 while(1){
698 pobj_c->ActionVtblSchedule(ImageBase,MemPos_CodeSection);
699
700 if(pobj_c->pobj_NextClass==0) break;
701 pobj_c=pobj_c->pobj_NextClass;
702 }
703 }
704 }
705}
706
707CClass *CDBClass::check(const char *name){
708 int key;
709 key=hash(name);
710
711 if(pobj_ClassHash[key]){
712 CClass *pobj_c;
713 pobj_c=pobj_ClassHash[key];
714 while(1){
715 if(lstrcmp(name,pobj_c->name)==0){
716 //重複した場合
717 return pobj_c;
718 }
719
720 if(pobj_c->pobj_NextClass==0) break;
721 pobj_c=pobj_c->pobj_NextClass;
722 }
723 }
724 return 0;
725}
726
727CClass *CDBClass::AddClass(const char *name,int nowLine){
728 //////////////////////////////////////////////////////////////////////////
729 // クラスを追加
730 // ※名前のみを登録。その他の情報はSetClassメソッドで!
731 //////////////////////////////////////////////////////////////////////////
732
733 CClass *pobj_c;
734 pobj_c=new CClass(name);
735
736 if(lstrcmp(name,"String")==0){
737 //Stringクラス
738 pobj_StringClass=pobj_c;
739 }
740 if( lstrcmp( name, "Object" ) == 0 ){
741 pObjectClass = pobj_c;
742 }
743
744
745 /////////////////////////////////
746 // ハッシュデータに追加
747 /////////////////////////////////
748
749 int key;
750 key=hash(name);
751
752 if(pobj_ClassHash[key]){
753 CClass *pobj_c2;
754 pobj_c2=pobj_ClassHash[key];
755 while(1){
756 if(lstrcmp(name,pobj_c2->name)==0){
757 //重複した場合
758 SetError(15,name,nowLine);
759 return 0;
760 }
761
762 if(pobj_c2->pobj_NextClass==0) break;
763 pobj_c2=pobj_c2->pobj_NextClass;
764 }
765 pobj_c2->pobj_NextClass=pobj_c;
766 }
767 else{
768 pobj_ClassHash[key]=pobj_c;
769 }
770
771 return pobj_c;
772}
773
774void CDBClass::InitNames(void){
775 extern char *basbuf;
776 int i;
777
778 for(i=0;;i++){
779 if(basbuf[i]=='\0') break;
780
781 if(basbuf[i]==1&&(
782 basbuf[i+1]==ESC_CLASS||
783 basbuf[i+1]==ESC_TYPE||
784 basbuf[i+1]==ESC_INTERFACE
785 )){
786 int nowLine;
787 nowLine=i;
788
789 i+=2;
790 //アラインメント修飾子
791 if(memicmp(basbuf+i,"Align(",6)==0){
792 i+=6;
793 i=JumpStringInPare(basbuf,i)+1;
794 }
795
796 int i2;
797 char temporary[VN_SIZE];
798 for(i2=0;;i++,i2++){
799 if(!IsVariableChar(basbuf[i])){
800 temporary[i2]=0;
801 break;
802 }
803 temporary[i2]=basbuf[i];
804 }
805
806 //クラスを追加
807 CClass *pClass = pobj_DBClass->AddClass(temporary,nowLine);
808 if( pClass ){
809 if( basbuf[nowLine+1] == ESC_CLASS ){
810 pClass->classType = CClass::Class;
811 }
812 else if( basbuf[nowLine+1] == ESC_INTERFACE ){
813 pClass->classType = CClass::Interface;
814 }
815 else{
816 pClass->classType = CClass::Structure;
817 }
818 }
819 }
820 }
821}
822
823
824void CDBClass::AddMethod(CClass *pobj_c, DWORD dwAccess, BOOL bStatic, bool isConst, BOOL bAbstract,
825 BOOL bVirtual, BOOL bOverride, char *buffer, int nowLine){
826 int i,i2;
827 char temporary[VN_SIZE];
828
829 i=2;
830 for(i2=0;;i++,i2++){
831 if(buffer[i]=='('||buffer[i]=='\0'){
832 temporary[i2]=0;
833 break;
834 }
835 temporary[i2]=buffer[i];
836 }
837
838
839 //関数ハッシュへ登録
840 UserProc *pUserProc;
841 pUserProc=AddSubData(buffer,nowLine,bVirtual,pobj_c, (bStatic!=0) );
842 if(!pUserProc) return;
843
844
845 ////////////////////////////////////////////////////////////
846 // コンストラクタ、デストラクタの場合の処理
847 ////////////////////////////////////////////////////////////
848 BOOL fConstructor=0,bDestructor=0;
849
850 if(lstrcmp(temporary,pobj_c->name)==0){
851 //コンストラクタの場合
852
853 //標準コンストラクタ(引数なし)
854 if(pUserProc->Params().size()==0) fConstructor=1;
855
856 //強制的にConst修飾子をつける
857 isConst = true;
858 }
859 else if(temporary[0]=='~'){
860 //デストラクタの場合はその名前が正しいかチェックを行う
861 if(lstrcmp(temporary+1,pobj_c->name)!=0)
862 SetError(117,NULL,nowLine);
863 else
864 bDestructor=1;
865 }
866 if(fConstructor||bDestructor){
867 // コンストラクタ、デストラクタのアクセシビリティをチェック
868
869 //強制的にConst修飾子をつける
870 isConst = true;
871 }
872
873 if( fConstructor == 1 )
874 pobj_c->ConstructorMemberSubIndex = (int)pobj_c->methods.size();
875 else if( bDestructor )
876 pobj_c->DestructorMemberSubIndex = (int)pobj_c->methods.size();
877
878
879
880 //////////////////
881 // 重複チェック
882 //////////////////
883
884 if(pobj_c->DupliCheckMember(temporary)){
885 SetError(15,temporary,nowLine);
886 return;
887 }
888
889 //メソッド
890 foreach( CMethod *method, pobj_c->methods ){
891 //基底クラスと重複する場合はオーバーライドを行う
892 if(method->pobj_InheritsClass) continue;
893
894 if( method->pUserProc->GetName() == temporary ){
895 if( Parameter::Equals( method->pUserProc->Params(), pUserProc->Params() ) ){
896 //関数名、パラメータ属性が合致したとき
897 SetError(15,pUserProc->GetName().c_str(),nowLine);
898 return;
899 }
900 }
901 }
902
903 //仮想関数の場合
904 if(bAbstract) pUserProc->CompleteCompile();
905
906 //メソッドのオーバーライド
907 foreach( CMethod *method, pobj_c->methods ){
908 if( method->pUserProc->GetName() == temporary ){
909 if( Parameter::Equals( method->pUserProc->Params(), pUserProc->Params() ) ){
910
911 if(method->bVirtual){
912 //メンバ関数を上書き
913 method->pUserProc=pUserProc;
914 method->bAbstract=0;
915
916 if(!bOverride){
917 SetError(127,NULL,nowLine);
918 }
919 if(method->dwAccess!=dwAccess){
920 SetError(128,NULL,nowLine);
921 }
922
923 pUserProc->SetMethod( method );
924 return;
925 }
926 }
927 }
928 }
929
930 if(bVirtual){
931 pobj_c->vtbl_num++;
932 }
933
934 if(bOverride){
935 SetError(12,"Override",nowLine);
936 }
937
938 if(bStatic){
939 pobj_c->AddStaticMethod(pUserProc,dwAccess);
940 }
941 else{
942 pobj_c->AddMethod(pUserProc, dwAccess, isConst, bAbstract, bVirtual);
943 }
944}
945
946BOOL CDBClass::MemberVar_LoopRefCheck(const CClass &objClass){
947 int i,i2,bRet=1;
948 for(i=0;i<objClass.iMemberNum;i++){
949 const CMember *pMember = objClass.ppobj_Member[i];
950 if(pMember->IsStruct()){
951 //循環参照でないかをチェック
952 if(pobj_LoopRefCheck->check(pMember->GetClass().name)){
953 extern int cp;
954 SetError(124,pMember->GetClass().name,cp);
955 return 0;
956 }
957
958 pobj_LoopRefCheck->add(objClass.name);
959
960 i2=MemberVar_LoopRefCheck(pMember->GetClass());
961 if(bRet==1) bRet=i2;
962
963 pobj_LoopRefCheck->del(objClass.name);
964 }
965 }
966
967 return bRet;
968}
969
970void CDBClass::GetClass_recur(const char *lpszInheritsClass){
971 extern char *basbuf;
972 int i,i2,i3,sub_address,top_pos;
973 DWORD dwAccess;
974 char temporary[8192];
975
976 for(i=0;;i++){
977 if(basbuf[i]=='\0') break;
978
979 CClass *pobj_c;
980
981 if(basbuf[i]==1&&basbuf[i+1]==ESC_INTERFACE){
982 //////////////////////////
983 // インターフェイス
984 //////////////////////////
985
986 top_pos=i;
987
988 i+=2;
989
990 //インターフェイス名を取得
991 GetIdentifierToken( temporary, basbuf, i );
992
993 pobj_c=pobj_DBClass->check(temporary);
994 if(!pobj_c) continue;
995
996 if(lpszInheritsClass){
997 if(lstrcmp(lpszInheritsClass,pobj_c->name)!=0){
998 //継承先先読み用
999 continue;
1000 }
1001 }
1002
1003 if(pobj_c->ppobj_Member){
1004 //既に先読みされているとき
1005 continue;
1006 }
1007
1008 //メンバ用メモリを初期化
1009 pobj_c->ppobj_Member=(CMember **)HeapAlloc(hHeap,0,1);
1010 pobj_c->iMemberNum=0;
1011
1012 pobj_c->ConstructorMemberSubIndex=-1;
1013 pobj_c->DestructorMemberSubIndex=-1;
1014
1015 if(basbuf[i+1]==1&&basbuf[i+2]==ESC_INHERITS){
1016 //継承を行う場合
1017 for(i+=3,i2=0;;i++,i2++){
1018 if(IsCommandDelimitation(basbuf[i])){
1019 temporary[i2]=0;
1020 break;
1021 }
1022 temporary[i2]=basbuf[i];
1023 }
1024
1025 if(lstrcmpi(temporary,pobj_c->name)==0){
1026 SetError(105,temporary,i);
1027 goto Interface_InheritsError;
1028 }
1029
1030 //継承元クラスを取得
1031 CClass *pInheritsClass = check(temporary);
1032 if( !pInheritsClass ){
1033 SetError(106,temporary,i);
1034 goto Interface_InheritsError;
1035 }
1036
1037 //ループ継承でないかをチェック
1038 if(pobj_LoopRefCheck->check(temporary)){
1039 SetError(123,temporary,i);
1040 goto Interface_InheritsError;
1041 }
1042
1043 if( pInheritsClass->ppobj_Member == 0 ){
1044 //継承先が読み取られていないとき
1045 pobj_LoopRefCheck->add(pobj_c->name);
1046 GetClass_recur(temporary);
1047 pobj_LoopRefCheck->del(pobj_c->name);
1048 }
1049
1050 //継承させる
1051 pobj_c->Inherits( pInheritsClass );
1052 }
1053 else{
1054 //継承無し
1055 pobj_c->pobj_InheritsClass=0;
1056
1057 //仮想関数の数を初期化
1058 pobj_c->vtbl_num=0;
1059 }
1060Interface_InheritsError:
1061
1062 //メンバ変数、関数を取得
1063 while(1){
1064 i++;
1065
1066 //エラー
1067 if(basbuf[i]==1&&(basbuf[i+1]==ESC_CLASS||basbuf[i+1]==ESC_TYPE||basbuf[i+1]==ESC_INTERFACE)){
1068 SetError(22,"Interface",i);
1069 i--;
1070 break;
1071 }
1072
1073 if(basbuf[i]==1&&basbuf[i+1]==ESC_INHERITS){
1074 SetError(111,NULL,i);
1075 break;
1076 }
1077
1078 sub_address=i;
1079
1080 for(i2=0;;i++,i2++){
1081 if(IsCommandDelimitation(basbuf[i])){
1082 temporary[i2]=0;
1083 break;
1084 }
1085 temporary[i2]=basbuf[i];
1086 }
1087 if(temporary[0]=='\0'){
1088 if(basbuf[i]=='\0'){
1089 i--;
1090 SetError(22,"Interface",top_pos);
1091 break;
1092 }
1093 continue;
1094 }
1095
1096 //End Interface記述の場合
1097 if(temporary[0]==1&&temporary[1]==ESC_ENDINTERFACE) break;
1098
1099 if(!(temporary[0]==1&&(
1100 temporary[1]==ESC_SUB||temporary[1]==ESC_FUNCTION
1101 ))){
1102 SetError(1,NULL,i);
1103 break;
1104 }
1105
1106 //メンバ関数を追加
1107 AddMethod(pobj_c,
1108 ACCESS_PUBLIC, //Publicアクセス権
1109 0, //Static指定なし
1110 false, //Constではない
1111 1, //Abstract
1112 1, //Virtual
1113 0,
1114 temporary,
1115 sub_address
1116 );
1117 }
1118 }
1119
1120 if(basbuf[i]==1&&(basbuf[i+1]==ESC_CLASS||basbuf[i+1]==ESC_TYPE)){
1121 //////////////////////////
1122 // クラス
1123 //////////////////////////
1124
1125 top_pos=i;
1126
1127 const DWORD dwClassType=basbuf[i+1];
1128
1129 i+=2;
1130
1131 //アラインメント修飾子
1132 int iAlign=0;
1133 if(memicmp(basbuf+i,"Align(",6)==0){
1134 i+=6;
1135 i+=GetStringInPare_RemovePare(temporary,basbuf+i)+1;
1136 iAlign=atoi(temporary);
1137
1138 if(!(iAlign==1||iAlign==2||iAlign==4||iAlign==8||iAlign==16))
1139 SetError(51,NULL,i);
1140 }
1141
1142
1143 //クラス名を取得
1144 GetIdentifierToken( temporary, basbuf, i );
1145
1146 pobj_c=pobj_DBClass->check(temporary);
1147 if(!pobj_c) continue;
1148
1149 if(lpszInheritsClass){
1150 if(lstrcmp(lpszInheritsClass,pobj_c->name)!=0){
1151 //継承先先読み用
1152 continue;
1153 }
1154 }
1155
1156 if(pobj_c->ppobj_Member){
1157 //既に先読みされているとき
1158 continue;
1159 }
1160
1161 pobj_c->iAlign=iAlign;
1162
1163 //メンバ用メモリを初期化
1164 pobj_c->ppobj_Member=(CMember **)HeapAlloc(hHeap,0,1);
1165 pobj_c->iMemberNum=0;
1166
1167 pobj_c->ConstructorMemberSubIndex=-1;
1168 pobj_c->DestructorMemberSubIndex=-1;
1169
1170 //アクセス制限の初期値をセット
1171 if(dwClassType==ESC_CLASS) dwAccess=ACCESS_PRIVATE;
1172 else dwAccess=ACCESS_PUBLIC;
1173
1174 if( lstrcmp( pobj_c->name, "Object" ) == 0 || dwClassType == ESC_TYPE ){
1175 //継承無し
1176 pobj_c->pobj_InheritsClass=0;
1177
1178 //仮想関数の数を初期化
1179 pobj_c->vtbl_num=0;
1180 }
1181 else{
1182 if(basbuf[i+1]==1&&basbuf[i+2]==ESC_INHERITS){
1183 //継承を行う場合
1184 for(i+=3,i2=0;;i++,i2++){
1185 if(IsCommandDelimitation(basbuf[i])){
1186 temporary[i2]=0;
1187 break;
1188 }
1189 temporary[i2]=basbuf[i];
1190 }
1191
1192 if(lstrcmpi(temporary,pobj_c->name)==0){
1193 SetError(105,temporary,i);
1194 goto InheritsError;
1195 }
1196 }
1197 else{
1198 //Objectを継承する
1199 lstrcpy( temporary, "Object" );
1200 }
1201
1202 //継承元クラスを取得
1203 CClass *pInheritsClass = check(temporary);
1204 if( !pInheritsClass ){
1205 SetError(106,temporary,i);
1206 goto InheritsError;
1207 }
1208
1209 //ループ継承でないかをチェック
1210 if(pobj_LoopRefCheck->check(temporary)){
1211 SetError(123,temporary,i);
1212 goto InheritsError;
1213 }
1214
1215 if( pInheritsClass->ppobj_Member == 0 ){
1216 //継承先が読み取られていないとき
1217 pobj_LoopRefCheck->add(pobj_c->name);
1218 GetClass_recur(temporary);
1219 pobj_LoopRefCheck->del(pobj_c->name);
1220 }
1221
1222 //継承させる
1223 pobj_c->Inherits( pInheritsClass );
1224 }
1225InheritsError:
1226
1227 //メンバとメソッドを取得
1228 while(1){
1229 i++;
1230
1231 //エラー
1232 if(basbuf[i]==1&&(basbuf[i+1]==ESC_CLASS||basbuf[i+1]==ESC_TYPE)){
1233 SetError(22,"Class",i);
1234 i--;
1235 break;
1236 }
1237
1238 if(basbuf[i]==1&&basbuf[i+1]==ESC_INHERITS){
1239 SetError(111,NULL,i);
1240 break;
1241 }
1242
1243 //Static修飾子
1244 BOOL bStatic;
1245 if(basbuf[i]==1&&basbuf[i+1]==ESC_STATIC){
1246 bStatic=1;
1247 i+=2;
1248 }
1249 else bStatic=0;
1250
1251 //Const修飾子
1252 bool isConst = false;
1253 if( basbuf[i] == 1 && basbuf[i + 1] == ESC_CONST ){
1254 isConst = true;
1255 i += 2;
1256 }
1257/*
1258 //Ref修飾子
1259 bool isRef = false;
1260 if( basbuf[i] == 1 && basbuf[i + 1] == ESC_BYREF ){
1261 isRef = true;
1262 i += 2;
1263 }*/
1264
1265 if(basbuf[i]==1&&(
1266 basbuf[i+1]==ESC_ABSTRACT||basbuf[i+1]==ESC_VIRTUAL||basbuf[i+1]==ESC_OVERRIDE||
1267 basbuf[i+1]==ESC_SUB||basbuf[i+1]==ESC_FUNCTION
1268 )){
1269 i3=basbuf[i+1];
1270 sub_address=i;
1271 }
1272 else i3=0;
1273
1274 BOOL bVirtual=0,bAbstract=0,bOverride=0;
1275 if(i3==ESC_ABSTRACT){
1276 bAbstract=1;
1277 bVirtual=1;
1278 i+=2;
1279
1280 i3=basbuf[i+1];
1281 }
1282 else if(i3==ESC_VIRTUAL){
1283 bAbstract=0;
1284 bVirtual=1;
1285 i+=2;
1286
1287 i3=basbuf[i+1];
1288 }
1289 else if(i3==ESC_OVERRIDE){
1290 bOverride=1;
1291 bVirtual=1;
1292
1293 i+=2;
1294
1295 i3=basbuf[i+1];
1296 }
1297
1298 for(i2=0;;i++,i2++){
1299 if(IsCommandDelimitation(basbuf[i])){
1300 temporary[i2]=0;
1301 break;
1302 }
1303 temporary[i2]=basbuf[i];
1304 }
1305 if(temporary[0]=='\0'){
1306 if(basbuf[i]=='\0'){
1307
1308 if(dwClassType==ESC_CLASS)
1309 SetError(22,"Class",top_pos);
1310 else
1311 SetError(22,"Type",top_pos);
1312
1313 i--;
1314 break;
1315 }
1316 continue;
1317 }
1318
1319 //End Class記述の場合
1320 if(temporary[0]==1&&temporary[1]==ESC_ENDCLASS&&dwClassType==ESC_CLASS) break;
1321 if(temporary[0]==1&&temporary[1]==ESC_ENDTYPE&&dwClassType==ESC_TYPE) break;
1322
1323 //アクセスを変更
1324 if(lstrcmpi(temporary,"Private")==0){
1325 dwAccess=ACCESS_PRIVATE;
1326 continue;
1327 }
1328 if(lstrcmpi(temporary,"Public")==0){
1329 dwAccess=ACCESS_PUBLIC;
1330 continue;
1331 }
1332 if(lstrcmpi(temporary,"Protected")==0){
1333 dwAccess=ACCESS_PROTECTED;
1334 continue;
1335 }
1336
1337 extern int cp;
1338 if(i3==0){
1339 if(bStatic){
1340 //静的メンバを追加
1341 cp=i; //エラー用
1342 pobj_c->AddStaticMember( dwAccess, isConst, false, temporary, i);
1343 }
1344 else{
1345 //メンバを追加
1346 cp=i; //エラー用
1347 pobj_c->AddMember( dwAccess, isConst, false, temporary );
1348
1349
1350 if(pobj_c->ppobj_Member[pobj_c->iMemberNum-1]->IsStruct()){
1351 if(pobj_c->ppobj_Member[pobj_c->iMemberNum-1]->GetClass().ppobj_Member==0){
1352 //参照先が読み取られていないとき
1353 GetClass_recur(pobj_c->ppobj_Member[pobj_c->iMemberNum-1]->GetClass().name);
1354 }
1355 }
1356
1357
1358 if(pobj_c->ppobj_Member[pobj_c->iMemberNum-1]->IsStruct()){
1359 //循環参照のチェック
1360 pobj_LoopRefCheck->add(pobj_c->name);
1361 if(!MemberVar_LoopRefCheck(pobj_c->ppobj_Member[pobj_c->iMemberNum-1]->GetClass())){
1362 //エラー回避
1363 pobj_c->ppobj_Member[pobj_c->iMemberNum-1]->SetBasicType( DEF_PTR_VOID );
1364 }
1365 pobj_LoopRefCheck->del(pobj_c->name);
1366 }
1367 }
1368 }
1369 else{
1370 //メソッドを追加
1371 cp=i; //エラー用
1372 AddMethod(pobj_c,
1373 dwAccess,
1374 bStatic,
1375 isConst,
1376 bAbstract,
1377 bVirtual,
1378 bOverride,
1379 temporary,
1380 sub_address);
1381
1382 if(bAbstract) continue;
1383
1384 for(;;i++){
1385 if(basbuf[i]=='\0'){
1386 i--;
1387 break;
1388 }
1389 if(basbuf[i-1]!='*'&&
1390 basbuf[i]==1&&(
1391 basbuf[i+1]==ESC_SUB||
1392 basbuf[i+1]==ESC_FUNCTION||
1393 basbuf[i+1]==ESC_MACRO||
1394 basbuf[i+1]==ESC_TYPE||
1395 basbuf[i+1]==ESC_CLASS||
1396 basbuf[i+1]==ESC_INTERFACE||
1397 basbuf[i+1]==ESC_ENUM)){
1398 GetDefaultNameFromES(i3,temporary);
1399 SetError(22,temporary,i);
1400 }
1401 if(basbuf[i]==1&&basbuf[i+1]==GetEndXXXCommand((char)i3)){
1402 i+=2;
1403 break;
1404 }
1405 }
1406 }
1407 }
1408 }
1409 }
1410}
1411
1412void CDBClass::GetAllClassInfo(void){
1413 //ループ継承チェック用のクラス
1414 pobj_LoopRefCheck=new CLoopRefCheck();
1415
1416 //クラスを取得
1417 GetClass_recur(0);
1418
1419 delete pobj_LoopRefCheck;
1420 pobj_LoopRefCheck=0;
1421
1422 // イテレータ用のデータを作る
1423 pobj_DBClass->Iterator_Init();
1424}
1425
1426void CDBClass::Compile_System_InitializeUserTypes(){
1427
1428 ////////////////////////////////////////////////////////////////////
1429 // クラス登録
1430 ////////////////////////////////////////////////////////////////////
1431
1432 // イテレータをリセット
1433 Iterator_Reset();
1434
1435 while( Iterator_HasNext() ){
1436 CClass *pClass = Iterator_GetNext();
1437
1438 char temporary[VN_SIZE];
1439 sprintf( temporary
1440 , "Add(%c%c_System_TypeForClass(\"%s\",\"%s\"))"
1441 , 1
1442 , ESC_NEW
1443 , "" // 名前空間 (TODO: 実装)
1444 , pClass->name // クラス名
1445 );
1446
1447 // コンパイル
1448 ChangeOpcode( temporary );
1449
1450 // ネイティブコードバッファの再確保
1451 ReallocNativeCodeBuffer();
1452 }
1453
1454
1455 ////////////////////////////////////////////////////////////////////
1456 // 継承関係登録
1457 ////////////////////////////////////////////////////////////////////
1458 // TODO: 未完成
1459 /*
1460
1461 // イテレータをリセット
1462 Iterator_Reset();
1463
1464 while( Iterator_HasNext() ){
1465 CClass *pClass = Iterator_GetNext();
1466
1467 sprintf( genBuffer + length
1468 , "obj.Search( \"%s\" ).SetBaseType( Search( \"%s\" ) ):"
1469 , "" // クラス名
1470 , pClass->name // クラス名
1471 );
1472 length += lstrlen( genBuffer + length );
1473
1474 while( length + 8192 > max ){
1475 max += 8192;
1476 genBuffer = (char *)realloc( genBuffer, max );
1477 }
1478 }*/
1479}
1480
1481
1482
1483CClass *CDBClass::GetStringClass() const
1484{
1485 if( !pStringClass ){
1486 SetError();
1487 return NULL;
1488 }
1489 return pStringClass;
1490}
1491CClass *CDBClass::GetObjectClass() const
1492{
1493 if( !pObjectClass ){
1494 SetError();
1495 return NULL;
1496 }
1497 return pObjectClass;
1498}
1499
1500void CDBClass::StartCompile( UserProc *pUserProc ){
1501 pCompilingClass = pUserProc->GetParentClassPtr();
1502 if( pCompilingClass ){
1503 pCompilingMethod = pCompilingClass->GetMethodInfo( pUserProc );
1504 if( !pCompilingMethod ){
1505 pCompilingMethod = pCompilingClass->GetStaticMethodInfo( pUserProc );
1506 if( !pCompilingMethod ){
1507 SetError(300,NULL,cp);
1508 }
1509 }
1510 }
1511 else{
1512 pCompilingMethod = NULL;
1513 }
1514}
1515CClass *CDBClass::GetNowCompilingClass(){
1516 return pCompilingClass;
1517}
1518CMethod *CDBClass::GetNowCompilingMethodInfo(){
1519 return pCompilingMethod;
1520}
1521
1522
1523
1524
1525//////////////////////
1526// イテレータ
1527//////////////////////
1528
1529void CDBClass::Iterator_Init(void){
1530 if(ppobj_IteClass) HeapDefaultFree(ppobj_IteClass);
1531
1532 iIteMaxNum=0;
1533 iIteNextNum=0;
1534 ppobj_IteClass=(CClass **)HeapAlloc(hHeap,0,1);
1535
1536 int i;
1537 for(i=0;i<MAX_CLASS_HASH;i++){
1538 if(pobj_ClassHash[i]){
1539 CClass *pobj_c;
1540 pobj_c=pobj_ClassHash[i];
1541 while(1){
1542 ppobj_IteClass=(CClass **)HeapReAlloc(hHeap,0,ppobj_IteClass,(iIteMaxNum+1)*sizeof(CClass *));
1543 ppobj_IteClass[iIteMaxNum]=pobj_c;
1544 iIteMaxNum++;
1545
1546 if(pobj_c->pobj_NextClass==0) break;
1547 pobj_c=pobj_c->pobj_NextClass;
1548 }
1549 }
1550 }
1551}
1552void CDBClass::Iterator_Reset(void){
1553 iIteNextNum = 0;
1554}
1555BOOL CDBClass::Iterator_HasNext(void){
1556 if(iIteNextNum<iIteMaxNum) return 1;
1557 return 0;
1558}
1559CClass *CDBClass::Iterator_GetNext(void){
1560 CClass *pobj_c;
1561 pobj_c=ppobj_IteClass[iIteNextNum];
1562 iIteNextNum++;
1563 return pobj_c;
1564}
1565int CDBClass::Iterator_GetMaxCount(void){
1566 return iIteMaxNum;
1567}
Note: See TracBrowser for help on using the repository browser.