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: func 02.11.06 0.0.A.
11 *
12 * Author: Alexander Krivonogov ( algen )
13 *
14 * Summary: Обработка функции, метода, свойства
15 *
16 ******************************************************************************/
17
18 #include "func.h"
19 #include "bcodes.h"
20 #include "out.h"
21 #include "alias.h"
22
23 s_funcdata fd;
24
25 /*-----------------------------------------------------------------------------
26 *
27 * ID: m_func 02.11.06 0.0.A.
28 *
29 * Summary: The func, method, operator, property, text processing
30 *
31 -----------------------------------------------------------------------------*/
32 plexem STDCALL m_func( plexem curlex, uint flgextern )
33 {
34 #ifdef DOUT
35 uint i;
36 #endif
37
38
39 uint funckey; //Вид функции
40 uint flgfunc; //Флаги функции
41
42 pflabel curlabel; // Текущий элемент в таблице меток
43 pflabel endlabel; // Конец таблицы меток
44 uint isreturn; //Есть return
45
46 uint thistype; //Тип переменной this для методов+
47 pubyte name; //Имя функции
48 plexem lexname; //Лексема с именем функции
49
50 s_desctype desctype;//Описание типа
51 s_descid descvar; //Описание переменной
52
53 uint off_parcount; //Смещение в заголовке функции на кол. параметров
54 uint off_blccount; //Смещение в заголовке функции на кол. блоков
55
56 bcflag bcf; //Переменная для получение флагов функции
57 pbuf b;
58 pfwith pwith;
59 pvmobj funcobj;
60 uint thisid; //Номер переменной для this в текст функции
61
62 D( "Func start\n" );
63
64 // Инициализация
65 desctype.idtype = 0;
66 descvar.idtype = 0;
67 descvar.flgdesc = 0;
68 mem_zero( &fd, sizeof( fd ) );
69 thistype = 0;
70 funckey = curlex->key;
71 hash_init( &fd.nvars, sizeof( uint ) );
72 hash_init( &fd.nlabels, sizeof( uint ) );
73 for ( b = &fd.bhead; b <= &fd.bvarsas; b++ )
74 {
75 buf_init( b );
76 buf_reserve( b, 0x200 );
77 b->step = 0x200;
78 }
79 fd.bvars.use = sizeof( fvar );
80 fd.blabels.use = sizeof( flabel );
81 // _compile->pout = &fd.bhead;
82 // fd.blcount = 0;
83 // fd.varcount = 0;
84 // fd.curcount = 0;
85 // fd.lastcurcount = 0;
86 // fd.bllevel = 0;
87 // fd.blcycle = 0;
88 fd.offlcbreak = -1;
89 fd.offlccontinue = -1;
90 // fd.functype = 0;
91
92 switch ( funckey )
93 {
94 case KEY_METHOD:
95 flgfunc = GHBC_METHOD;
96 break;
97 case KEY_OPERATOR:
98 flgfunc = GHBC_OPERATOR;
99 break;
100 case KEY_PROPERTY:
101 flgfunc = GHBC_PROPERTY;
102 break;
103 case KEY_TEXT:
104 flgfunc = GHBC_TEXT;
105 break;
106 default:
107 flgfunc = 0;
108 }
109 curlex = lexem_next( curlex, LEXNEXT_IGNLINE );
110
111 // Получаем тип возвращаемого значения функции/метода если он есть
112 if ( curlex->type == LEXEM_NAME )
113 curlex = desc_idtype( curlex, &desctype );
114
115 if ( desctype.idtype )
116 {
117 if ( ( funckey == KEY_METHOD || funckey == KEY_PROPERTY ) &&
118 curlex->type == LEXEM_OPER &&
119 curlex->oper.operid == OpWith )
120 {
121 //Возврат на лексему влево текущая лексема тип объекта
122 desctype.idtype = 0;
123 curlex--;
124 }
125 else
126 {
127 fd.functype = desctype.idtype;
128 fd.funcoftype = desctype.oftype;
129 }
130 }
131 curlex = lexem_next( curlex, LEXNEXT_SKIPLINE );
132 // Получаем тип объекта для метода
133 if ( funckey == KEY_METHOD || funckey == KEY_PROPERTY )
134 {
135 //Получаем тип объекта
136 if ( thistype = bc_type( curlex ) )
137 {
138 curlex = lexem_next( curlex, 0 );
139 if ( curlex->type == LEXEM_OPER &&
140 curlex->oper.operid == OpWith )
141 {
142 curlex = lexem_next( curlex, 0 );
143 }
144 else
145 msg( MExppoint | MSG_LEXERR, curlex );
146 }
147 else
148 msg( MExptype | MSG_LEXERR, curlex );
149 }
150 // Получение имени функции, метода ...
151 if ( funckey == KEY_OPERATOR )
152 {
153 if ( curlex->type != LEXEM_OPER )
154 msg( MExpoper | MSG_LEXERR, curlex );
155 name = ( pubyte )&curlex->oper.name;
156 }
157 else
158 {
159 if ( curlex->type != LEXEM_NAME )
160 msg( MExpname | MSG_LEXERR, curlex );
161 name = lexem_getname( curlex );
162 }
163 lexname = curlex;
164 _vm.pos = curlex->pos;
165
166 // Получение списка директив
167 curlex = lexem_next( curlex, flgextern ? 0 : LEXNEXT_IGNLINE );
168 curlex = bc_flag( curlex, BFLAG_FUNC, &bcf );
169 flgfunc |= GHCOM_NAME | bcf.value;
170 _compile->pout = &fd.bhead;
171 out_head( OVM_BYTECODE, flgfunc, name );
172
173 create_varmode( &fd.bhead, &desctype, 0 );//Возвращаемое значение
174
175 off_parcount = fd.bhead.use;
176 out_adduint( 0 );//Количество параметров
177
178 if ( funckey == KEY_METHOD || funckey == KEY_PROPERTY )
179 { //Создание параметра this
180 mem_zero( &descvar, sizeof( descvar ));
181 descvar.idtype = thistype;
182 descvar.name = "this";
183 descvar.lex = curlex;
184 descvar.flgdesc = DESCID_PARFUNC;
185
186 pwith = ( pfwith )buf_appendtype( &fd.bwith, sizeof( fwith )) ;
187 pwith->num = var_checkadd( &descvar );
188 pwith->oftype = 0;
189 pwith->type = thistype;
190 }
191
192 //Получение списка параметров
193 if ( curlex->type == LEXEM_OPER &&
194 curlex->oper.operid == OpLbrack )//Открывающая скобка
195 {
196 curlex = lexem_next( curlex, LEXNEXT_IGNLINE );
197 curlex = var_def( curlex, DESCID_PARFUNC );
198 if ( curlex->type != LEXEM_OPER ||//Системная лексема
199 curlex->oper.operid != OpRbrack )//Закрывающая скобка
200 msg( MExpclosebr | MSG_LEXERR, curlex );
201
202 curlex = lexem_next( curlex, flgextern ? 0 : LEXNEXT_IGNLINE );
203 }
204 else
205 {
206 if ( funckey == KEY_OPERATOR )
207 msg( MExpopenbr | MSG_LEXERR, curlex );
208 }
209
210 fd.flgfunc = flgfunc;
211 if ( flgfunc & GHBC_RESULT )
212 { //Создание параметра result
213 if ( !fd.functype || fd.functype <= TUlong )
214 msg( MResulttype | MSG_LEXERR, curlex );
215 mem_zero( &descvar, sizeof( descvar ));
216 descvar.idtype = desctype.idtype;
217 descvar.oftype = desctype.oftype;
218 descvar.flgdesc = DESCID_PARFUNC;
219 descvar.name = "result";
220 descvar.lex = curlex;
221 fd.idresult = var_checkadd( &descvar );
222 fd.functype = 0;
223 }
224 if ( fd.varcount )
225 {
226 *( puint )( fd.bhead.data + off_parcount ) = fd.varcount;//Кол-во параметров
227 if ( flgfunc & ( GHBC_ENTRY | GHBC_MAIN ) )
228 msg( MMainpar | MSG_LEXERR, curlex );
229 fd.curcount = 0;
230 }
231 off_blccount = fd.bhead.use;
232 out_adduint( 0 );//Количество блоков
233
234 if ( funckey == KEY_PROPERTY )
235 {
236 if ( ( fd.functype && fd.varcount > 1 ) ||
237 (!fd.functype && fd.varcount != 2 ))
238 {
239 msg( MProppar | MSG_LEXERR, curlex );//Неверное количество параметров в описании свойства
240 }
241 if ( type_fieldname( thistype, name ) )
242 {
243 msg( MPropfield | MSG_LEXERR, curlex );//Свойство совпадает с именем поля
244 }
245 }
246
247 funcobj = load_bytecode( &fd.bhead.data, flgextern ? VMLOAD_EXTERN : VMLOAD_FIRST );
248 if ( bcf.value & GHRT_ALIAS )
249 {
250 alias_setid( bcf.alias, funcobj->id );
251 }
252 if ( !( flgextern ) )
253 {
254 if ( _compile->flag & CMPL_DEBUG )
255 {
256 _compile->pout = fd.bout = &fd.bsubout;
257 out_adduints( 3, CDatasize,
258 str_len( _compile->cur->filename ) + 5,
259 str_pos2line( _compile->cur->src, lexname->pos, 0 ) + 1 );
260 out_addptr( str_ptr( _compile->cur->filename ), str_len( _compile->cur->filename ) + 1 );
261 out_adduint( CDbgFunc );
262 _compile->pout = fd.bout = &fd.bfuncout;
263 }
264 _compile->pout = fd.bout = &fd.bfuncout;
265 if ( funckey == KEY_TEXT )
266 { //Создание параметра this для Text функции
267 mem_zero( &descvar, sizeof( descvar ));
268 descvar.idtype = TUint;
269 descvar.name = "this";
270 descvar.lex = curlex;
271 descvar.flgdesc = DESCID_VAR;///DESCID_PARFUNC;
272 thisid = var_checkadd( &descvar );
273
274 /*pwith = ( pfwith )buf_appendtype( &fd.bwith, sizeof( fwith )) ;
275 pwith->num = var_checkadd( &descvar );
276 //print( "ssssssssss %x %x %x %x", fd.bvars.data, fd.bvars.use, pwith->num, sizeof( fvar ) );
277 pwith->oftype = 0;
278 pwith->type = TStr;*/
279 ((pfvar)(fd.bvars.data + fd.bvars.use - sizeof( fvar )))->type = TStr;
280 out_adduints( 4, CVarptrload, thisid, CGetText, CSetI );
281 /*buf_appenduint( &fd.bblinit, CVarptrload );
282 buf_appenduint( &fd.bblinit, thisid );
283 buf_appenduint( &fd.bblinit, CGetText );
284 buf_appenduint( &fd.bblinit, CSetI );*/
285 }
286 curlex = f_body( curlex );
287
288 *((puint)(fd.bhead.data+off_blccount)) = fd.blcount;
289
290 curlabel = ( pflabel )( fd.blabels.data ) + 1;
291 endlabel = ( pflabel )( fd.blabels.data + fd.blabels.use );
292 //Контроль неразрешённых меток и проверка выходов из функции
293 isreturn = 0;
294 while( curlabel < endlabel )
295 {
296 if ( curlabel->type & LABT_GT )
297 {
298 if ( ( curlabel->type & LABT_GTUNDEF ) == LABT_GTUNDEF )
299 msg( MUnklabel | MSG_LEXNAMEERR, curlabel->lex );
300 *( puint )(fd.bfuncout.data + curlabel->offbout ) =
301 ((( pflabel )(fd.blabels.data + curlabel->link ))->offbout +
302 fd.bsubout.use )/sizeof(uint);
303 if ( !isreturn )//Помечаем метку как отработавшую (на неё был переход)
304 (( pflabel )(fd.blabels.data + curlabel->link ))->type |= LABT_LABELWORK;
305 }
306 else
307 if ( curlabel->type & LABT_RETURN )
308 {
309 isreturn = 1;//Устанавливаем флаг
310 }
311 else
312 if ( curlabel->type & LABT_LABELWORK )
313 isreturn = 0;//Если была отработавшая метка, то сбрасываем флаг
314 curlabel++;
315 }
316 if ( fd.functype )
317 {
318 if ( !isreturn )
319 msg( MMustret | MSG_LEXNAMEERR, lexname );
320 }
321 else
322 if ( !isreturn )
323 {
324 if ( fd.flgfunc & GHBC_RESULT )
325 {
326 out_add2uint( CVarload, fd.idresult );
327 }
328 out_adduint( CReturn );
329 }
330 buf_add( &fd.bhead, &fd.bvardef );
331
332 if ( fd.bsubout.use )
333 {
334 if ( fd.offsubgoto )
335 {
336 //*((( puint)fd.bsubout.data ) + 1) = fd.bsubout.use/sizeof( uint );
337 *( puint )( fd.bsubout.data + fd.offsubgoto ) = fd.bsubout.use / sizeof( uint );
338 }
339 buf_add( &fd.bhead, &fd.bsubout );
340 }
341 buf_add( &fd.bhead, &fd.bfuncout );
342 _compile->pout = &fd.bhead;
343 out_finish();
344 #ifdef DOUT
345 //Тестируемый вывод
346 //if ( name[0] == 'c' && name[1] == 'r' ) getch();
347 print( "FUNC OUT %x %s:\n", funcobj->id, name );
348 for (i = 0; i < fd.bhead.use ; i++ )
349 {
350 print( " %x", fd.bhead.data[i] );
351 }
352 print( "\n" );
353 #endif
354 load_bytecode( &fd.bhead.data, VMLOAD_OK );
355 // print( "funcobjid2 =%x\n", funcobj->id );
356 }
357 //Очистка памяти
358 for ( b = &fd.bhead;/*&fd.bblinit;*/ b <= &fd.bvarsas; b++ )
359 {
360 buf_delete( b );
361 }
362 hash_delete( &fd.nvars );
363 hash_delete( &fd.nlabels );
364
365 D( "Func Stop\n" );
366 return curlex;
367 }
368
369