-
Notifications
You must be signed in to change notification settings - Fork 0
/
Type.cpp
5584 lines (4687 loc) · 218 KB
/
Type.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//=============================================================================
// Описание классов типов (Type)
//=============================================================================
#include "Stat.h"
#include "Type.h"
#include "Var.h"
//-----------------------------------------------------------------------------
//инициализация списка родительского объекта объектами-переменными
int CIdentList::AssignVars(CLexBuf *lb)
{
//загрузка списка идентификаторов
int err_num = LoadIdentList(lb);
if (err_num) return err_num;
//в случае именованного типа необходимо проверять его экспорт при экспорте переменной данного типа
//CBaseType* BT = NULL; //ук. на тип можно не получать пока он реально не потребуется
//создание объявленных переменных по указанному типу
CBaseNameVector::iterator vi;
for (vi = BNVector.begin(); vi != BNVector.end(); ++vi) {
CIdentDef* IdentDef = static_cast<CIdentDef*>(*vi);
//создание переменной требуемого типа
CBaseVar* BaseVar;
err_num = BaseType->CreateVar(BaseVar, parent_element);
if (err_num) return err_num;
//установка параметров переменной по ее описанию в списке идентификаторов
err_num = IdentDef->AssignVar(BaseVar);
if (err_num) {
delete BaseVar;
return err_num;
}
//проверка получения неспециализированной обобщенной переменной
if (id_CCommonVar == BaseVar->name_id && static_cast<CCommonVar*>(BaseVar)->IsPureCommon()) {
//попытка получить имя специализации по умолчанию
//получение типа обобщение
CBaseType* CT;
if (id_CQualidentType == BaseType->name_id) {
err_num = static_cast<CQualidentType*>(BaseType)->GetNamedType(CT, false);
if (err_num) return err_num;
} else
CT = BaseType;
if (id_CCommonType != CT->name_id) return s_e_CommonTypeExpected;
const CCommonType::SSpec* spec = static_cast<CCommonType*>(CT)->GetDefaultSpec();
if (!spec) {
//специализация по умолчанию не найдена, выдача сообщения об ошибке
delete BaseVar;
return s_e_SpecTypeExpected;
}
//установка имени специализации по умолчанию
err_num = static_cast<CCommonVar*>(BaseVar)->SetTagName(spec->QualName, spec->Name);
if (err_num) return err_num;
}
//занесение полученной переменной в список
parent_element->AddName(BaseVar);
}
return 0;
}//CIdentList::AssignVars
//-----------------------------------------------------------------------------
//деструктор объекта CDeclSeq
CDeclSeq::~CDeclSeq()
{
CBaseNameVector::const_iterator ci;
for(ci = BaseNameStore.begin(); ci != BaseNameStore.end(); ++ci)
delete *ci;
delete DfnModuleSeq;
}//~CDeclSeq
/**/
/*
//-----------------------------------------------------------------------------
//распечатка DeclSeq (таблицы имен)
void CDeclSeq::debug_PutsDeclSeq()
{
char *st = new char[MaxStLeng];
strcpy(st, "===== Name table (");
strcat(st, parent_element->name);
strcat(st, ") =====");
puts(st);
BaseNameList_type::iterator i;
for(i = BaseNameList.begin(); i != BaseNameList.end(); ++i)
switch ((*i)->name_id) {
case id_CQualidentType:
case id_CArrayType:
case id_CRecordType:
case id_CPointerType:
case id_CSetType:
case id_CLongrealType:
case id_CRealType:
case id_CLongintType:
case id_CIntegerType:
case id_CShortintType:
case id_CCharType:
case id_CBooleanType:
case id_CProcedureType:
strcpy(st, (*i)->name);
strcat( st, " = TYPE");
puts(st);
break;
case id_CForwardDecl:
strcpy(st, (*i)->name);
strcat( st, " = PROCEDURE^ (Forward)");
puts(st);
break;
case id_CProcedure:
strcpy(st, (*i)->name);
strcat( st, " = PROCEDURE");
puts(st);
break;
case id_CDfnProcedure:
strcpy(st, (*i)->name);
strcat( st, " = PROCEDURE (DFN)");
puts(st);
break;
case id_CArrayVar:
case id_CRecordVar:
case id_CPointerVar:
case id_CProcedureVar:
case id_CLongrealVar:
case id_CRealVar:
case id_CLongintVar:
case id_CIntegerVar:
case id_CShortintVar:
case id_CCharVar:
case id_CBooleanVar:
case id_CSetVar:
strcpy(st, (*i)->name);
strcat( st, " = VAR");
puts(st);
break;
case id_CImportModule:
//Imported table
const char* r_n = ((CImportModule*)(*i))->real_name;
CDfnModule* DM = NULL;
if (DfnModuleSeq) DM = DfnModuleSeq->FindName(r_n);
if (DM) DM->DfnDeclSeq->debug_PutsDeclSeq();
break;
default:
int num = (*i)->name_id;
puts((*i)->name);
};//switch
strcpy(st, "----- end table (");
strcat(st, parent_element->name);
strcat(st, ") ------");
puts(st);
}//PutsDeclSeq
*/
//-----------------------------------------------------------------------------
//инициализация объекта CDeclSeq
int CDeclSeq::Init(CLexBuf *lb)
{
DECL_SAVE_POS
//буфер для чтения информации о текущей лексеме
CLexInfo li;
//переменная для получения номера ошибки
int err_num;
//проверка наличия ключевого слова (отсутствие ошибок чтения)
if (!lb->ReadLex(li) || lex_k_dot > li.lex) return s_e_END;
//проверка наличия послед-сти деклараций CONST, TYPE, VAR
while (true) {
//тип блока деклараций (константы, типы, переменные)
enum {dkCONST, dkTYPE, dkVAR} DeclKind;
//проверка полученной лексемы
if (lex_k_CONST == li.lex) DeclKind = dkCONST;
else
if (lex_k_TYPE == li.lex) DeclKind = dkTYPE;
else
if (lex_k_VAR == li.lex) DeclKind = dkVAR;
else
break;
//обработка послед-ти деклараций (или CONST, или TYPE, или VAR)
while(true) {
//перед поиском необязательного эл-та запоминаем позицию
SAVE_POS
//поиск необязательного эл-та (в завис-ти от вида декларации)
switch (DeclKind) {
case dkCONST:
err_num = ConstInit(lb);
break;
case dkTYPE:
err_num = TypeInit(lb);
break;
case dkVAR:
err_num = VarInit(lb);
break;
}
//проверка инициализации одиночной декларации
if (err_num == s_m_IdentDefAbsent) {
//выход, если не нашли декларацию (восст. позицию)
RESTORE_POS
break;
}
//проверка отсутствия ошибок инициализации декларации
if (err_num) return err_num;
//чтение кл. слова ";"
if (!lb->ReadLex(li) || lex_k_semicolon != li.lex)
return s_e_SemicolonMissing;
}//while
SAVE_POS
//проверка наличия ключевого слова (отсутствие ошибок чтения)
if (!lb->ReadLex(li) || (lex_k_dot > li.lex))
return s_e_BEGIN;
}//while
//выполнение доп. проверок корректности таблицы имен
err_num = CheckCompleteRoot(lb);
if (err_num) return err_num;
//проверка наличия послед-сти деклараций PROCEDURE, PROCEDURE ^
while (lex_k_PROCEDURE == li.lex) {
err_num = ProcInit(lb);
if (err_num) return err_num;
//чтение кл. слова ";"
if (!lb->ReadLex(li) || lex_k_semicolon != li.lex) return s_e_SemicolonMissing;
SAVE_POS
//проверка наличия ключевого слова (отсутствие ошибок чтения)
if (!lb->ReadLex(li) || (lex_k_dot > li.lex))
return s_e_BEGIN;
}
//последняя считанная лексема не из DeclSeq
RESTORE_POS
return 0;
}//CDeclSeq::Init
//-----------------------------------------------------------------------------
//добавление импортируемых модулей в список деклараций
int CDeclSeq::ImportListInit(const CProject *project, CLexBuf *lb)
{
DECL_SAVE_POS
//буфер для чтения информации о текущей лексеме
CLexInfo li;
//проверка наличия кл. слова IMPORT
if (!lb->ReadLex(li) || lex_k_IMPORT != li.lex) {
//нет списка импорта - восстанавливаем позицию
RESTORE_POS
return 0;
}
else {
while (true) {
//есть список импорта - загружаем его
CImportModule *ImpMod = new CImportModule(parent_element);
int err_num = ImpMod->Init(lb);
if (err_num) {
delete ImpMod;
return err_num;
}
//проверка отсутствия имени в таблице имен (DeclSeq)
if (FindName(ImpMod->name)) {
delete ImpMod;
return s_e_Redefinition;
}
//занесение считанного объекта в список
AddName(ImpMod);
//проверка отсутствия импортирования самого себя
if (!strcmp(parent_element->name, ImpMod->real_name))
return s_e_RecursiveImport;
//загрузка dfn импортированного модуля
err_num = LoadDfnModule(project, ImpMod->real_name, ImpMod->name);
if (err_num) return err_num;
//проверка наличия ","
if (!lb->ReadLex(li) || lex_k_comma != li.lex) break;
}
//проверка наличия ";"
if (lex_k_semicolon != li.lex) return s_e_SemicolonMissing;
}
return 0;
}//CDeclSeq::ImportListInit
//-----------------------------------------------------------------------------
//Запись кода CDeclSeq для типов
int CDeclSeq::WriteCPP_type(CPP_files& f)
{
if (id_CModule == parent_element->name_id) fprintf(f.fc, "\n//IMPORT\n");
CBaseNameVector::const_iterator ci;
//запись кода импортируемых модулей
for (ci = BaseNameStore.begin(); ci != BaseNameStore.end(); ++ci) {
if (id_CImportModule == (*ci)->name_id) {
(*ci)->WriteCPP(f);
//отделение namespace'ов друг от друга
fprintf(f.fc, "\n");
}
}
//запись кода обычных типов (все глобальные типы пишутся в заголовочный файл, т.к.
//они могут использоваться при экспорте переменной)
for (ci = BaseNameStore.begin(); ci != BaseNameStore.end(); ++ci)
if (CBaseType::IsTypeId((*ci)->name_id)) {
//проверка, является ли тип глобальным, если нет - проверка признака наличия '*'
bool to_h = (id_CModule == (*ci)->parent_element->name_id) || (*ci)->external;
//проверка, является ли тип записью (для записей вначале пишется только объявление)
if (id_CRecordType == (*ci)->name_id)
fprintf(to_h ? f.fh : f.fc, "struct %s;\n", (*ci)->name);
else //обычная запись кода объявления типа
static_cast<CBaseType*>(*ci)->WriteCPP(f, to_h);
}
//генерация кода описаний типа запись (до этого были сгенерированы только объявления,
//это необходимо, т.к. в методе могут использоваться еще не объявленные на момент объявления
//записи типы, а объявление метода помещается в код записи)
for (ci = BaseNameStore.begin(); ci != BaseNameStore.end(); ++ci)
if (id_CRecordType == (*ci)->name_id) {
//проверка, является ли тип глобальным, если нет - проверка признака наличия '*'
bool to_h = (id_CModule == (*ci)->parent_element->name_id) || (*ci)->external;
//описание типа запись
static_cast<CRecordType*>(*ci)->WriteCPP(f, to_h);
}
return 0;
}//WriteCPP_type
//-----------------------------------------------------------------------------
//Запись кода CDeclSeq для процедур
int CDeclSeq::WriteCPP_proc(CPP_files& f)
{
CBaseNameVector::const_iterator ci;
for (ci = BaseNameStore.begin(); ci != BaseNameStore.end(); ++ci)
if (CProcedure::IsProcId((*ci)->name_id)) {
fprintf(f.fc, "\n%s", comment_line_cpp);
(*ci)->WriteCPP(f);
}
return 0;
}//WriteCPP_proc
//-----------------------------------------------------------------------------
//Запись кода CDeclSeq для переменных
int CDeclSeq::WriteCPP_var(CPP_files& f)
{
//признак глобальности всех деклараций в данной таблице имен
bool is_global = id_CModule == parent_element->name_id;
//запись комментария начала описания переменных
fprintf(f.fc, "%s//VAR\n", id_CModule == parent_element->name_id ? "\n" : "");
//цикл перебора переменных
CBaseNameVector::const_iterator ci;
for(ci = BaseNameStore.begin(); ci != BaseNameStore.end(); ++ci)
if (CBaseVar::IsVarId((*ci)->name_id)) {
//проверка необходимости включения переменной в безымянное пространство имен
//(необходимо для глобальных неэкспортированных переменных)
bool req_unnm_space = is_global && !(*ci)->external;
if (req_unnm_space) fprintf(f.fc, "namespace {");
//генерация кода переменной
(*ci)->WriteCPP(f);
//отделение переменных друг от друга с записью '}' (если необходимо закрыть пространство имен)
fprintf(f.fc, ";%s\n", req_unnm_space ? "}" : "");
//отделение переменных в .h файле
if ((*ci)->external) fprintf(f.fh, ";\n");
}
return 0;
}//WriteCPP
//-----------------------------------------------------------------------------
//Запись в .dfn файл
void CDeclSeq::WriteDFN(DFN_file& f)
{
//увеличение отступа в DFN файле
f.tab_level++;
CBaseNameVector::const_iterator i;
//признак отсутствия эл-тов в категории, имеющей заголовок (IMPORT, CONST, TYPE, VAR)
bool no_elems(true);
//запись кода импортируемых модулей
for (i = BaseNameStore.begin(); i != BaseNameStore.end(); ++i)
if ( (*i)->name_id == id_CImportModule )
{
//проверка первого импортированного модуля
if (no_elems) {
no_elems = false;
fprintf(f.f, "\nIMPORT\n\t");
} else
fprintf(f.f, ", ");
//запись кода текущего модуля
(*i)->WriteDFN(f);
}
if (!no_elems) fprintf(f.f, ";\n");
//запись кода экспортируемых констант
no_elems = true;
for (i = BaseNameStore.begin(); i != BaseNameStore.end(); ++i)
if ( (*i)->external && CBaseVar::IsVarId((*i)->name_id) && static_cast<CBaseVar*>(*i)->is_const ) {
//проверка 1-й экспортируемой константы
if (no_elems) {
no_elems = false;
fprintf(f.f, "\nCONST\n\t");
} else
fprintf(f.f, "\t");
//запись кода текущей константы
(*i)->WriteDFN(f);
fprintf(f.f, ";\n");
}
//запись кода экспортируемых типов
no_elems = true;
for (i = BaseNameStore.begin(); i != BaseNameStore.end(); ++i)
if ( (*i)->external && CBaseType::IsTypeId((*i)->name_id) )
{
//проверка первого экспортируемого типа
if (no_elems) {
no_elems = false;
fprintf(f.f, "\nTYPE\n\t");
} else
fprintf(f.f, "\t");
//запись кода текущего типа
fprintf(f.f, "%s = ", (*i)->name);
(*i)->WriteDFN(f);
fprintf(f.f, ";\n");
}
//запись кода экспортируемых переменных
no_elems = true;
for(i = BaseNameStore.begin(); i != BaseNameStore.end(); ++i)
if ( (*i)->external &&
((*i)->name_id != id_CImportModule) &&
!CProcedure::IsProcId((*i)->name_id) &&
!CBaseType::IsTypeId((*i)->name_id) &&
!(CBaseVar::IsVarId((*i)->name_id) && static_cast<CBaseVar*>(*i)->is_const) )
{
//проверка первой экспортируемой переменной
if (no_elems) {
no_elems = false;
fprintf(f.f, "\nVAR\n\t");
} else
fprintf(f.f, "\t");
//запись кода текущей переменной
(*i)->WriteDFN(f);
fprintf(f.f, ";\n");
}
//запись кода экспортируемых процедур
for(i = BaseNameStore.begin(); i != BaseNameStore.end(); ++i)
if ((*i)->external && (id_CProcedure == (*i)->name_id || id_CCommonProc == (*i)->name_id))
{
fprintf(f.f, "\n");
(*i)->WriteDFN(f);
fprintf(f.f, ";");
}
//уменьшение отступа в DFN файле
f.tab_level--;
}//WriteDFN
//-----------------------------------------------------------------------------
//поиск имени в таблице имен, NULL - если имя не найдено
CBaseName* CDeclSeq::FindName(const char* search_name) const
{
CBaseNameVector::const_iterator ci;
for (ci = BaseNameStore.begin(); ci != BaseNameStore.end(); ci++)
if (!strcmp((*ci)->name, search_name))
return *ci;
return NULL;
}//FindName
//-----------------------------------------------------------------------------
//добавление указанного эл-та в таблицу имен
void CDeclSeq::AddName(CBaseName* BN) const
{
BaseNameStore.push_back(BN);
}
//-----------------------------------------------------------------------------
//инициализация объекта TYPE из потока лексем
int CDeclSeq::TypeInit(CLexBuf *lb)
{
//создание имени IdentDef
CIdentDef IdentDef(parent_element, false);
int err_num = IdentDef.Init(lb);
//проверка наличия имени (может не быть) и отсутствия ошибок (могут быть)
if (err_num) {
if (s_e_IdentExpected == err_num)
return s_m_IdentDefAbsent; //нет идентификатора - это не ошибка
else
return err_num; //есть некорректно помеченный идент. - это ошибка
}
//буфер для чтения информации о текущей лексеме
CLexInfo li;
DECL_SAVE_POS
//проверка наличия кл. слова "=" или "+="
if (!lb->ReadLex(li)) return s_e_EqualSignExpected;
//ук. на объект (создаваемый или расширяемый тип)
CBaseType *BaseType = NULL;
//проверка типа полученной лексемы: "=", "+=", "." (часть описания расширения)
switch (li.lex) {
//обычное описание типа
case lex_k_eq:
//создание объекта типа из потока лексем
err_num = TypeSelector(lb, BaseType, parent_element);
if (err_num) return err_num;
//занесение имени объекта в созданный объект
IdentDef.Assign(BaseType);
//проверка отсутствия имени в таблице имен (DeclSeq)
if (FindName(BaseType->name)) return s_e_Redefinition;
//проверка наличия объекта тип RECORD и создание RuntimeId, если надо
if (id_CRecordType == BaseType->name_id) {
err_num = static_cast<CRecordType*>(BaseType)->InitRuntimeId();
if (err_num) return err_num;
}
//занесение считанного объекта в список
AddName(BaseType);
return 0;
//начало описания расширения импортированного обобщения
case lex_k_dot:
//получение названия импортированного обобщения
if (!lb->ReadLex(li) || lex_i != li.lex) return s_e_IdentExpected;
//поиск импортированного обобщения в таблицах имен
BaseType = static_cast<CBaseType*>(parent_element->GetGlobalName(IdentDef.name, li.st));
if (!BaseType) return s_e_UndeclaredIdent;
if (id_CCommonType != BaseType->name_id) return s_e_CommonTypeExpected;
//проверка наличия "+="
if (!lb->ReadLex(li) || lex_k_add_assign != li.lex) return s_e_AddAssignMissing;
//проверка отсутствия признака локальности у расширяемого обобщения
if (static_cast<CCommonType*>(BaseType)->IsLocal) return s_e_CommonTypeLocalExt;
//инициализация расширения импортированного обобщения
return static_cast<CCommonType*>(BaseType)->InitExtension(lb, this);
//описание расширения обобщения
case lex_k_add_assign:
//проверка отсутствия "*" (экспорт расширения не допускается)
if (IdentDef.external) {
RESTORE_POS
return s_e_IdentWrongMarked;
}
//проверка наличия расширения неимпортированного обобщения
if (!BaseType) {
BaseType = static_cast<CBaseType*>(parent_element->GetGlobalName(IdentDef.name));
if (!BaseType) {
RESTORE_POS
return s_e_UndeclaredIdent;
}
if (id_CCommonType != BaseType->name_id) {
RESTORE_POS
return s_e_CommonTypeExpected;
}
}
//инициализация расширения локального обобщения
return static_cast<CCommonType*>(BaseType)->InitExtension(lb, this);
//недопустимый символ
default:
return s_e_EqualSignExpected;
}//switch
}//CDeclSeq::TypeInit
//-----------------------------------------------------------------------------
//проверка завершенности всех объектов, входящих в пространство имен
int CDeclSeq::CheckCompleteRoot(CLexBuf *lb)
{
//для получения номера ошибки
int err_num;
//цикл перебора всех объявлений, входящих в пространство имен
CBaseNameVector::const_iterator ci;
for(ci = BaseNameStore.begin(); ci != BaseNameStore.end(); ++ci)
switch ((*ci)->name_id) {
//проверка отсутствия в таблице имен опережающего описания без соответствующей процедуры
case id_CForwardDecl:
if (!static_cast<CForwardDecl*>(*ci)->CheckSatisfied(lb)) return s_e_ForwardDeclUnsat;
continue;
//проверка завершенности типа указатель на именованный тип
case id_CPointerType:
err_num = static_cast<CPointerType*>(*ci)->CheckComplete(lb);
if (err_num) return err_num;
continue;
//проверка завершенности типа запись
case id_CRecordType:
err_num = static_cast<CRecordType*>(*ci)->CheckComplete(lb);
if (err_num) return err_num;
continue;
//проверка завершенности типа массив
case id_CArrayType:
err_num = static_cast<CArrayType*>(*ci)->CheckComplete(lb);
if (err_num) return err_num;
continue;
default:
//проверка завершенности текущей переменной
if (CBaseVar::IsVarId((*ci)->name_id)) {
err_num = static_cast<CBaseVar*>(*ci)->CheckComplete(lb);
if (err_num) return err_num;
}
}//switch
//проверка завершена
return 0;
}
//-----------------------------------------------------------------------------
//инициализация объекта CONST из потока лексем
int CDeclSeq::ConstInit(CLexBuf *lb)
{
//создание имени IdentDef
CIdentDef IdentDef(parent_element, false);
if (IdentDef.Init(lb)) return s_m_IdentDefAbsent; //нет ид-а (это НЕ ошибка)
//буфер для чтения информации о текущей лексеме
CLexInfo li;
//проверка наличия кл. слова =
if (!lb->ReadLex(li) || lex_k_eq != li.lex) return s_e_EqualSignExpected;
//создание константы
CBaseVar* ConstVar;
int err_num = ConstSelector(lb, ConstVar, parent_element);
if (err_num) return err_num;
//инициализация параметров константы согласно IdentDef
err_num = IdentDef.AssignVar(ConstVar);
if (err_num) return err_num;
//установка признака константы
ConstVar->is_const = true;
//занесение полученной константы в таблицу имен
parent_element->AddName(ConstVar);
return 0;
}//CDeclSeq::ConstInit
//-----------------------------------------------------------------------------
//инициализация объекта PROCEDURE ([^]) из потока лексем
int CDeclSeq::ProcInit(CLexBuf *lb)
{
DECL_SAVE_POS
//буфер для чтения информации о текущей лексеме
CLexInfo li;
//для временного хранения создаваемого объекта
CProcedure *Proc;
//для перебора контейнера объявлений
CBaseNameVector::const_iterator ci;
//проверка отсутствия кл. слова ^
if (!lb->ReadLex(li) || lex_k_up_arrow != li.lex) {
//инициализация процедуры
RESTORE_POS
Proc = new CProcedure(parent_element);
} else //инициализация опережающего описания процедуры
Proc = new CForwardDecl(parent_element);
//инициализация процедуры и проверка отсутствия обобщений в ее параметрах
int err_num = Proc->Init(lb);
if (err_num && (s_m_CommonProcFound != err_num)) goto fault_exit;
//проверка обнаружения обобщенной процедуры
if (s_m_CommonProcFound == err_num) {
//найдена обобщающая процедура или обработчик
delete Proc;
//попытка инициализации обобщающей параметрической процедуры
RESTORE_POS
Proc = new CCommonProc(parent_element);
err_num = Proc->Init(lb);
if (err_num && (s_m_HProcFound != err_num)) goto fault_exit;
//проверка наличия обработчика парам. специализации
if (s_m_HProcFound == err_num) {
//найден обработчик парам. специализации - уничтожаем CCommonProc
delete Proc;
//инициализация обработчика парам. специализации
RESTORE_POS
Proc = new CHandlerProc(parent_element);
err_num = Proc->Init(lb);
if (err_num) goto fault_exit;
}
//проверка наличия другого обработчика с совпадающим списком параметров выполняется линковщиком
AddName(Proc);
return 0;
}
//проверка наличия в данной области видимости других объектов с совпадающим именем
for (ci = BaseNameStore.begin(); ci != BaseNameStore.end(); ci++)
if (CProcedure::IsProcId((*ci)->name_id)) {
if (Proc->CompareProcNames(static_cast<CProcedure*>(*ci))) {
//найдены два объекта с совпадающими именами (включая приемники),
//допустимо наличие объявленного опережающего описания (иначе - ошибка)
if (id_CForwardDecl != (*ci)->name_id) {
RESTORE_POS
err_num = s_e_Redefinition;
goto fault_exit;
}
//в случае описания процедуры - проверка соответствия опережающему описанию
if (id_CForwardDecl != Proc->name_id) {
//проверка соответствия объявления процедуры ее опережающему описанию
err_num = static_cast<CForwardDecl*>(*ci)->CompareDeclarations(Proc);
if (err_num) {
RESTORE_POS
goto fault_exit;
}
}
}
} else {
//имена процедур, связанных с типом, не могут конфликтовать с глобальными именами
if (Proc->Receiver) continue;
//сравнение с именем объекта, не являющимся процедурой
if (!strcmp(Proc->name, (*ci)->name)) {
RESTORE_POS
err_num = s_e_Redefinition;
goto fault_exit;
}
}
//занесение считанного объекта в список
AddName(Proc);
return 0;
fault_exit:
//уничтожение временного объекта и возврат сообщения об ошибке
delete Proc;
return err_num;
}//CDeclSeq::ProcInit
//-----------------------------------------------------------------------------
//инициализация объекта VAR из потока лексем
int CDeclSeq::VarInit(CLexBuf *lb)
{
//создание списка имен переменных (с проверкой, является ли список списком локальных переменных)
CIdentList IdentList(parent_element, (parent_element->name_id != id_CModule) && (parent_element->name_id != id_CDfnModule));
//создание переменных по созданному списку имен
return IdentList.AssignVars(lb);
}//CDeclSeq::VarInit
//-----------------------------------------------------------------------------
//конструктор объекта CDfnModuleSeq
CDfnModuleSeq::CDfnModuleSeq(const CBaseName* parent) : parent_element(parent)
{
}
//-----------------------------------------------------------------------------
//деструктор объекта CDfnModuleSeq
CDfnModuleSeq::~CDfnModuleSeq()
{
DfnModuleList_type::iterator i;
for(i = DfnModuleList.begin(); i != DfnModuleList.end(); ++i)
delete (*i);
}//~CDfnModuleSeq
//-----------------------------------------------------------------------------
//запись в project названий всех файлов .dfn модуля (кроме себя)
void CDfnModuleSeq::EnumDfnModules(CProject &project)
{
if (DfnModuleList.empty()) return;
DfnModuleList_type::const_iterator ci;
for (ci = DfnModuleList.begin(); ci != DfnModuleList.end(); ++ci) {
//добавление очередного файла в список файлов (если его там нет)
project.AddMakeFile( (*ci)->full_path, (*ci)->name);
//запись файлов импортированных модулей
if ((*ci)->DfnDeclSeq->DfnModuleSeq)
(*ci)->DfnDeclSeq->DfnModuleSeq->EnumDfnModules(project);
}
}
//-----------------------------------------------------------------------------
//добавление эл-та в список модулей
void CDfnModuleSeq::AddModule(CDfnModule *DM)
{
DfnModuleList.push_back(DM);
}
//-----------------------------------------------------------------------------
//поиск имени в таблице имен, NULL - если имя не найдено
CDfnModule* CDfnModuleSeq::FindName(const char* search_name) const
{
DfnModuleList_type::const_iterator i;
for (i = DfnModuleList.begin(); i != DfnModuleList.end(); ++i)
if (!strcmp( (*i)->name, search_name ))
return *i;
return NULL;
}//FindName
//-----------------------------------------------------------------------------
//Запись кода CDfnModuleSeq
void CDfnModuleSeq::WriteCPP(CPP_files& f)
{
DfnModuleList_type::const_iterator i;
for (i = DfnModuleList.begin(); i != DfnModuleList.end(); ++i)
(*i)->WriteCPP(f);
}
//-----------------------------------------------------------------------------
//деструктор объекта MODULE
CModule::~CModule()
{
delete StatementSeq;
delete DeclSeq;
}//~CModule
//-----------------------------------------------------------------------------
//инициализация объекта MODULE
int CModule::Init(const CProject *project, CLexBuf *lb)
{
//буфер для чтения информации о текущей лексеме
CLexInfo li;
//проверка наличия кл. слова MODULE
if (!lb->ReadLex(li) || lex_k_MODULE != li.lex) return s_e_MODULE;
//проверка наличия названия модуля
if (!lb->ReadLex(li) || lex_i != li.lex) return s_e_IdentExpected;
if (!strcmp(li.st, "SYSTEM")) return s_e_MODULE_SYSTEM;
SetName(li.st);
//проверка наличия ";"
if (!lb->ReadLex(li) || lex_k_semicolon != li.lex) return s_e_SemicolonMissing;
//создание DeclSeq (для хранения импортируемых модулей)
DeclSeq = new CDeclSeq(this);
//загрузка списка импортируемых модулей (если есть)
int err_num = DeclSeq->ImportListInit(project, lb);
if (err_num) return err_num;
//проверка наличия DeclSeq
err_num = DeclSeq->Init(lb);
if (err_num) return err_num;
//чтение очередной лексемы (ключевого слова)
if (!lb->ReadLex(li) || lex_k_dot > li.lex) return s_e_END;
//проверка наличия операторов, если получен BEGIN
if (lex_k_BEGIN == li.lex) {
//проверка наличия послед. операторов
StatementSeq = new CStatementSeq(this);
err_num = StatementSeq->Init(lb);
if (err_num) return err_num;
//чтение очередной лексемы (ключевого слова)
if (!lb->ReadLex(li) || lex_k_dot > li.lex) return s_e_END;
}
//проверка наличия кл. слова MODULE END
if (lex_k_END != li.lex) return s_e_END;
//проверка наличия названия модуля (в конце)
if (!lb->ReadLex(li) || lex_i != li.lex) return s_e_IdentExpected;
if (strcmp(li.st, name)) return s_e_ModuleEndName;
//проверка наличия "."
if (!lb->ReadLex(li) || lex_k_dot != li.lex) return s_e_DotMissing;
return 0;
}//CModule::Init
//-----------------------------------------------------------------------------
//Запись кода CModule
void CModule::WriteCPP(CPP_files& f)
{
fprintf(f.fc, "//MODULE %s;\n", name);
fprintf(f.fc, "#include \"%s.h\"\n", name);
fprintf(f.fc, "using namespace %s;\n", name);
//генерация кода импортируемых модулей
if (DeclSeq->DfnModuleSeq) DeclSeq->DfnModuleSeq->WriteCPP(f);
//занесение деклараций в общее пространство имен
fprintf(f.fh, "namespace %s {\n", name);
//генерация кода деклараций типов
DeclSeq->WriteCPP_type(f);
//генерация кода переменных
DeclSeq->WriteCPP_var(f);
//генерация кода деклараций процедур
DeclSeq->WriteCPP_proc(f);
fprintf(f.fh, "//MODULE INITIALIZATION\nvoid %s%s();\n", O2M_SYS_, name);
fprintf(f.fc, "\n%s//MODULE INITIALIZATION\n", comment_line_cpp);
fprintf(f.fc, "void %s::%s%s() {\n", name, O2M_SYS_, name);
//инициализация импортируемых модулей
DeclSeq->WriteCPP_mod_init(f);
//генерация кода для операторов (если есть)
EHaveRet have_return = hr_No;
if (StatementSeq) {
have_return = StatementSeq->HaveRet();
StatementSeq->WriteCPP(f);
}
//код для реализации оператора RETURN (если есть RETURNы)
if (hr_No != have_return) fprintf(f.fc, "\tO2M_RETURN:;\n");
fprintf(f.fc, "}\n//END %s.\n", name);
}//WriteCPP
//-----------------------------------------------------------------------------
//поиск имени в таблице имен, NULL - если имя не найдено
CBaseName* CModule::FindName(const char* search_name) const
{
if (DeclSeq) return DeclSeq->FindName(search_name);
return NULL;
}
//-----------------------------------------------------------------------------
//добавление указанного эл-та в таблицу имен
void CModule::AddName(CBaseName* BN) const
{
DeclSeq->AddName(BN);
}
//-----------------------------------------------------------------------------
//инициализация объекта ImportModule
int CImportModule::Init(CLexBuf *lb)
{
//буфер для чтения информации о текущей лексеме
CLexInfo li;
//получение первого ид-а (имени модуля для использования)
if (!lb->ReadLex(li) || lex_i != li.lex) return s_e_IdentExpected;
SetName(li.st);
DECL_SAVE_POS
//проверка наличия кл. слова ":="
if (!lb->ReadLex(li) || lex_k_assign != li.lex) {
RESTORE_POS
real_name = str_new_copy(name);
return 0;
}
//получение второго ид-а (исходного имени модуля)
if (!lb->ReadLex(li) || lex_i != li.lex) return s_e_IdentExpected;
real_name = str_new_copy(li.st);
return 0;
}//CImportModule::Init
//-----------------------------------------------------------------------------
//Запись кода CImportModule
void CImportModule::WriteCPP(CPP_files& f)
{
//создание пространства имен при переименовании модуля
if (strcmp(name, real_name)) {
fprintf(f.fc, "//%s := %s\n", name, real_name);
fprintf(f.fc, "namespace %s {using namespace %s;}", name, real_name);
} else
fprintf(f.fc, "//%s", name);