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: for 09.02.07 0.0.A.
11 *
12 * Author: Alexander Krivonogov ( algen )
13 *
14 * Summary: Конструкции for, fornum
15 *
16 ******************************************************************************/
17
18 #include "func.h"
19 #include "bcodes.h"
20
21 /*-----------------------------------------------------------------------------
22 *
23 * ID: c_for 09.02.07 0.0.A.
24 *
25 * Summary: The for processing
26 *
27 -----------------------------------------------------------------------------*/
28 plexem STDCALL c_for( plexem curlex )
29 {
30 uint labbeg; //Метка начало
31 uint labend; //Метка конец
32 uint labcont; //Метка на continue
33 uint fd_offlcbreak; //Смещение в таблице меток
34 uint fd_offlccontinue;//Смещение в таблице меток
35 plexem incrlex; //Лесема начала выражения инкремента
36
37 D( "For start\n" );
38 fd.blcycle++;
39
40 //Обработка выражения инициализации
41 curlex = f_expr( curlex, EXPR_COMMA, 0, 0 );
42
43 if ( curlex->type != LEXEM_OPER || curlex->oper.operid != OpComma )
44 msg( MExpcomma | MSG_LEXERR, curlex );
45 curlex = lexem_next( curlex, 0 );
46
47 //Добавляем метку на начало
48 labbeg = j_label( LABT_LABELVIRT, -1 );
49
50 //Обработка логического выражения
51 curlex = f_expr( curlex, EXPR_BOOL | EXPR_COMMA, 0, 0 );
52 if ( curlex->type != LEXEM_OPER || curlex->oper.operid != OpComma )
53 msg( MExpcomma | MSG_LEXERR, curlex );
54 curlex = lexem_next( curlex, 0 );
55
56 //Сохраняем последние метки цикла
57 fd_offlcbreak = fd.offlcbreak;
58 fd_offlccontinue = fd.offlccontinue;
59
60 //Добавляем переход на конец
61 fd.offlcbreak = j_jump( CIfze, LABT_GTVIRT, -1);
62 fd.offlccontinue = -1;
63
64 //Пропуск инкремента
65 incrlex = curlex;
66 do
67 {
68 curlex = lexem_next( curlex, 0 );
69 }
70 while ( curlex->type != LEXEM_OPER || curlex->oper.operid != OpLcrbrack );
71
72 //Обработка тела
73 curlex = f_body( curlex );
74
75 //Метка на continue
76 labcont = j_label( LABT_LABELVIRT, -1 );
77
78 //Обработка инкремента
79 incrlex = f_expr( incrlex, 0, 0, 0 );
80 incrlex = lexem_next( incrlex, LEXNEXT_SKIPLINE );
81
82 if ( incrlex->type != LEXEM_OPER || incrlex->oper.operid != OpLcrbrack )
83 msg( MLcurly | MSG_LEXERR, incrlex );
84
85 //Добавляем переход на начало
86 j_jump( CGoto, LABT_GTVIRT, labbeg );
87
88 //Добавляем метку на конец
89 labend = j_label( LABT_LABELVIRT, -1 );
90
91 //Цикл установки переходов на конец
92 j_correct( fd.offlcbreak, labend );
93
94 //Цикл установки переходов на начало
95 j_correct( fd.offlccontinue, labcont );
96
97 //Восстановление меток цикла
98 fd.offlcbreak = fd_offlcbreak;
99 fd.offlccontinue = fd_offlccontinue;
100 fd.blcycle--;
101
102 D( "For stop\n" );
103 return curlex;
104 }
105
106
107 /*-----------------------------------------------------------------------------
108 *
109 * ID: c_fornum 09.02.07 0.0.A.
110 *
111 * Summary: The fornum processing
112 *
113 -----------------------------------------------------------------------------*/
114 #define INDEX_LOCVAR 0x1 //Индекс-переменная локальная
115 #define INDEX_GLOBVAR 0x2 //Индекс-переменная глобальная
116 plexem STDCALL c_fornum( plexem curlex )
117 {
118 plexem indexlex; //Лексема с переменной индекска
119 uint indexflg; //Флаг переменной индекса локальная/глобальная переменная
120 uint indexnum; //Номер/код переменной индекса
121 uint indextype; //Тип индекса
122
123 uint labbeg; //Метка начало
124 uint labend; //Метка конец
125 uint labcont; //Метка на continue
126
127 uint fd_offlcbreak; //Смещение в таблице меток
128 uint fd_offlccontinue;//Смещение в таблице меток
129
130 uint casenum; //Номер дополнительной переменной хранящей верхнее условие
131 uint globid; //Идентификатор глобальной переменной
132 pfvar var; //Указатель на структуру локальной переменной
133 phashiuint phitem; //Элемент хэштаблицы с локальной переменной
134 uint parsc[4]; //Параметры для получения кода операции
135
136 D( "Fornum start\n" );
137 fd.blcycle++;
138 indexlex = curlex;
139 indexflg = 0;
140
141 //Получение переменной индеска
142 phitem = (phashiuint)hash_find( &fd.nvars, lexem_getname( curlex ) );
143 if ( phitem )
144 { //Идентификатор есть в таблице локальных переменных
145 var = ( pfvar )(fd.bvars.data + phitem->val);
146 if ( !(var->flg ) )
147 { // Локальная переменная
148 indexnum = var->num;
149 indexflg = INDEX_LOCVAR;
150 indextype = var->type;
151 }
152 }
153 if ( !indexflg )
154 {
155 globid = bc_getid( curlex );
156 if ( globid && (( pvmobj )PCMD( globid ))->type == OVM_GLOBAL )
157 { //Глобальная переменная
158 indexnum = globid;
159 indexflg = INDEX_GLOBVAR;
160 indextype = ((povmglobal)PCMD( globid ))->type->type;
161 }
162 }
163 if ( !indexflg )
164 msg( MUnklex | MSG_LEXNAMEERR, curlex );//Неизвестный идентификатор
165 if ( indextype <= TInt || indextype >= TUshort )
166 msg( MVaruint | MSG_LEXERR, curlex );
167 parsc[0] = indextype;
168
169 //Обработка выражения инициализации
170 curlex = lexem_next( curlex, 0 );
171 if ( curlex->type == LEXEM_OPER && curlex->oper.operid == OpSet )
172 {
173 curlex = f_expr( indexlex, EXPR_COMMA, 0, 0 );
174 }
175
176
177 curlex = lexem_next( curlex, LEXNEXT_SKIPLINE );
178 if ( curlex->type != LEXEM_OPER || curlex->oper.operid != OpComma )
179 msg( MExpcomma | MSG_LEXERR, curlex );//Ошибка Должна быть запятая
180 curlex = lexem_next( curlex, 0 );
181
182 //Обработка выражения максимального значения
183 //Получение максимального значения и запись в локальную переменную
184 casenum = var_addtmp( indextype, 0 );
185 out_add2uint( CVarptrload, casenum );
186 curlex = f_expr( curlex, EXPR_NONULL, &parsc[2], &parsc[3] );
187
188 parsc[1] = 0;
189 out_adduint( bc_funcname( curlex, "#=", 2, parsc )->vmo.id );
190
191 //Добавляем метку на начало
192 labbeg = j_label( LABT_LABELVIRT, -1 );
193
194 out_debugtrace( curlex );
195 //Операция сравнения <
196 out_add2uint( indexflg & INDEX_LOCVAR ? CVarload : CPtrglobal,
197 indexnum );
198 if ( indexflg & INDEX_GLOBVAR )
199 {
200 out_adduint( CGetI );
201 }
202 out_adduints( 3, CVarload,
203 casenum,
204 bc_funcname( curlex, "#<", 2, parsc )->vmo.id );
205
206 //Сохраняем последние метки цикла
207 fd_offlcbreak = fd.offlcbreak;
208 fd_offlccontinue = fd.offlccontinue;
209
210 //Добавляем переход на конец
211 fd.offlcbreak = j_jump( CIfze, LABT_GTVIRT, -1);
212 fd.offlccontinue = -1;
213
214 //Обработка тела
215 curlex = f_body( curlex );
216
217 //Метка на continue
218 labcont = j_label( LABT_LABELVIRT, -1 );
219
220 //Обработка инкремента ++
221 out_adduints( 3, indexflg & INDEX_LOCVAR ? CVarptrload : CPtrglobal,
222 indexnum,
223 bc_funcname( curlex, "#++", 1, parsc )->vmo.id );
224
225 //Добавляем переход на начало
226 j_jump( CGoto, LABT_GTVIRT, labbeg );
227
228 //Добавляем метку на конец
229 labend = j_label( LABT_LABELVIRT, -1 );
230
231 //Цикл установки переходов на конец
232 j_correct( fd.offlcbreak, labend );
233
234 //Цикл установки переходов на начало
235 j_correct( fd.offlccontinue, labcont );
236
237 //Восстановление меток цикла
238 fd.offlcbreak = fd_offlcbreak;
239 fd.offlccontinue = fd_offlccontinue;
240 fd.blcycle--;
241
242 D( "Fornum stop\n" );
243 return curlex;
244 }
245