1 /******************************************************************************
2 *
3 * Copyright (C) 2006, The Gentee Group. All rights reserved.
4 * This file is part of the Gentee open source project - http://www.gentee.com.
5 *
6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT").
7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS
8 * ACCEPTANCE OF THE AGREEMENT.
9 *
10 * ID: foreach 09.02.07 0.0.A.
11 *
12 * Author: Alexander Krivonogov ( algen )
13 *
14 * Summary: The foreach statement
15 *
16 ******************************************************************************/
17
18 #include "func.h"
19 #include "bcodes.h"
20
21 /*-----------------------------------------------------------------------------
22 *
23 * ID: c_foreach 08.02.07 0.0.A.
24 *
25 * Summary: The foreach processing
26 *
27 -----------------------------------------------------------------------------*/
28 plexem STDCALL c_foreach( plexem curlex )
29 {
30 uint labbeg; //Метка начало
31 uint labend; //Метка конец
32 uint labcont; //Метка на continue
33 uint fd_offlcbreak; //Смещение в таблице меток
34 uint fd_offlccontinue; //Смещение в таблице меток
35 uint indexnum; //Номер/код переменной индекса
36 uint objnum; //Номер дополнительной переменной хранящей объект
37 uint fordata; //Номер переменной со структурой fordata
38
39 plexem indexlex; //Лексема с описанной переменной
40
41 uint objtype; //Тип объекта
42 uint itemtype; //Тип элемента
43 uint deftype; //Описанный тип элемента
44 uint vartype;
45
46 uint bcfirst; //Байт-код метода First
47 uint bceof; //Байт-код метода Eof
48 uint bcnext; //Байт-код метода Next
49 //uint bcset; //Байт-код присваивания значения
50 uint bcadvget; //Байт-код для дополнительного кода присваивания
51 uint bcadvset; //Байт-код для дополнительного кода присваивания
52
53 pfvar var; //Указатель на структуру локальной переменной
54 pfvaras varas; //Указатель на структуру as
55 phashiuint phitem; //Элемент хэштаблицы с локальной переменной
56 pubyte varname; //Имя локальной переменной
57 uint flgnewvar; //Флаг добавлять новую локальную переменную с индекском
58 s_descid descvar; //Структура для описания локальной переменной
59 uint offvar; //Смещение структуры локальной переменной
60
61 //pvmfunc pfunc; //Указатель на структуру операции
62 //uint parsc[4]; //Параметры для получения кода операции
63
64 D( "Foreach start\n" );
65 fd.blcycle++;
66
67 //Обработка индекса цикла
68
69 if ( curlex->type != LEXEM_NAME )
70 msg( MExpname | MSG_LEXERR, curlex );
71 vartype = bc_type( curlex );
72 if ( vartype )
73 {
74 curlex = lexem_next( curlex, LEXNEXT_IGNLINE );
75 }
76 if ( curlex->type != LEXEM_NAME )
77 msg( MExpname | MSG_LEXERR, curlex );
78
79 indexlex = curlex;
80
81 //Существует ли локальная переменная
82 phitem = (phashiuint)hash_find( &fd.nvars, lexem_getname( curlex ) );
83 //flgnewvar = 1;
84 if ( phitem && phitem->val &&
85 !(( var = (pfvar)( fd.bvars.data + ( offvar = phitem->val )))->flg & FVAR_SUBFUNC))
86 { //Идентификатор есть в таблице локальных переменных
87 flgnewvar = 0;
88 indexnum = var->num;
89 }
90 else
91 {
92 flgnewvar = 1;
93 varname = lexem_getname( curlex );
94 }
95 curlex = lexem_next( curlex, LEXNEXT_IGNLINE );
96 if ( curlex->type != LEXEM_OPER || curlex->oper.operid != OpComma )
97 msg( MExpcomma | MSG_LEXERR, curlex );
98 curlex = lexem_next( curlex, LEXNEXT_IGNLINE );
99
100 //Обработка выражения-объекта
101 objnum = var_addtmp( TUint, 0 ); //Создание переменной для хранения адреса объекта
102 out_add2uint( CVarptrload, objnum );//Байт код для сохранения результата выражения
103 curlex = f_expr( curlex, EXPR_NONULL, &objtype, &itemtype );
104 if ( !itemtype )
105 {
106 /*if ( ! (itemtype = (( povmtype)PCMD( objtype ))->index.type ))
107 itemtype = TUint;*/
108 itemtype = (( povmtype)PCMD( objtype ))->index.type;
109
110 }
111 out_adduint( CSetI );//Байт код загрузки значения
112 //Получаем байт-коды методов
113 bcfirst = bc_find( indexlex, "@first", 2, objtype, TAny );
114 bceof = bc_find( indexlex, "@eof", 2, objtype, TAny );
115 bcnext = bc_find( indexlex, "@next", 2, objtype, TAny );
116
117
118 if ( (( pvmfunc)PCMD( bcfirst ))->ret->type != TUint )
119 {
120 itemtype = (( pvmfunc)PCMD( bcfirst ))->ret->type;
121 deftype = TUint;
122 /*if ( !(itemtype = (( pvmfunc)PCMD( bcfirst ))->ret->type ))
123 {
124 itemtype = TUint;
125 }*/
126 }
127 fordata = var_addtmp((( pvmfunc)PCMD( bcfirst ))->params[1].type , 0 );
128
129 //Уточнение типов
130 if ( (( pvmobj )PCMD( itemtype ))->flag & GHTY_STACK )
131 {//Базовый тип элемента, приводим указатель к значению
132 //Предполагается что first/next могут возвращать только указатели
133 //Заполнение полей фиктивной лексемы
134 /*parsc[0] = itemtype;
135 parsc[1] = 0;
136 parsc[2] = itemtype;
137 parsc[3] = 0;
138 pfunc = bc_funcname( curlex, "#=", 2, parsc );*/
139 //bcset = CSetI;
140 bcadvget = artypes[ itemtype ];
141 bcadvset = (( povmtype )PCMD( itemtype ))->stsize == 1 ? CSetI : CSetL;
142 deftype = itemtype;
143 }
144 else
145 { //Тип элемента структура
146 //bcset = CSetI;
147 bcadvget = 0;
148 deftype = TUint;
149 }
150 if ( flgnewvar )
151 { //Создание новой локальной переменной-индекса
152 mem_zero( &descvar, sizeof( descvar ));
153 descvar.idtype = deftype;
154 descvar.name = varname;
155 descvar.lex = curlex;
156 descvar.flgdesc = DESCID_VAR;
157 offvar = fd.bvars.use;
158 indexnum = var_checkadd( &descvar );
159 }
160 var = (( pfvar )( fd.bvars.data + offvar ));
161 if ( deftype != ( var->flg & FVAR_UINTAS ? TUint : var->type ) ||
162 ( vartype && vartype != itemtype ) )
163 msg( MDiftypes | MSG_LEXERR, indexlex );
164 if ( !((( pvmobj )PCMD( itemtype ))->flag & GHTY_STACK) ||
165 var->flg & FVAR_UINTAS )
166 {
167 varas = ( pfvaras )buf_appendtype( &fd.bvarsas, sizeof( fvaras ) );
168
169 varas->offbvar = offvar;
170 varas->type = var->type;
171 varas->oftype = var->oftype;
172 varas->flg = var->flg;
173
174 var->type = itemtype;
175 var->oftype = 0;
176 var->flg |= FVAR_UINTAS;
177 }
178
179 //Добавляем вызов first
180 out_adduints( 8, CVarptrload,
181 indexnum,
182 CVarload,
183 objnum,
184 CVarload,
185 fordata,
186 bcfirst,
187 /*bcset*/CSetI );
188
189 //Добавляем метку на начало
190 labbeg = j_label( LABT_LABELVIRT, -1 );
191
192 out_debugtrace( curlex );
193
194 //Вызов метода Eof
195 //Обработка логического выражения
196 out_adduints( 5, CVarload,
197 objnum,
198 CVarload,
199 fordata,
200 bceof );
201
202 //Сохраняем последние метки цикла
203 fd_offlcbreak = fd.offlcbreak;
204 fd_offlccontinue = fd.offlccontinue;
205
206 //Добавляем переход на конец
207 fd.offlcbreak = j_jump( CIfnze, LABT_GTVIRT, -1);
208 fd.offlccontinue = -1;
209
210 if ( bcadvget )
211 {
212 //Коррекция для базовых типов
213 out_adduints( 7, CVarptrload,
214 indexnum,
215 CVarptrload,
216 indexnum,
217 CGetI,
218 bcadvget,
219 bcadvset );
220 /*out_adduints( 6, CVarptrload,
221 indexnum,
222 CVarload,
223 indexnum,
224 bcadvget,
225 bcset );*/
226 }
227
228 //Обработка тела
229 curlex = f_body( curlex );
230
231 //Метка на continue
232 labcont = j_label( LABT_LABELVIRT, -1 );
233
234 //Вызов метода Next
235 out_adduints( 8, CVarptrload,
236 indexnum,
237 CVarload,
238 objnum,
239 CVarload,
240 fordata,
241 bcnext,
242 /*bcset*/CSetI );
243
244 //Добавляем переход на начало
245 j_jump( CGoto, LABT_GTVIRT, labbeg );
246
247 //Добавляем метку на конец
248 labend = j_label( LABT_LABELVIRT, -1 );
249
250 //Цикл установки переходов на конец
251 j_correct( fd.offlcbreak, labend );
252
253 //Цикл установки переходов на начало
254 j_correct( fd.offlccontinue, labcont );
255
256 //Восстановление меток цикла
257 fd.offlcbreak = fd_offlcbreak;
258 fd.offlccontinue = fd_offlccontinue;
259 fd.blcycle--;
260
261 D( "Foreach stop\n" );
262 return curlex;
263 }