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: switch 08.02.07 0.0.A.
11 *
12 * Author: Alexander Krivonogov ( algen )
13 *
14 * Summary: The switch statement
15 *
16 ******************************************************************************/
17
18 #include "func.h"
19 #include "bcodes.h"
20
21 /*-----------------------------------------------------------------------------
22 *
23 * ID: c_if 08.02.07 0.0.A.
24 *
25 * Summary: The switch processing
26 *
27 -----------------------------------------------------------------------------*/
28 //Состояния для обработки switch
29 #define SWITCH_STFIRST 0x01 //Начальное состояние
30 #define SWITCH_STCASE 0x02 //Обработано условие очередного case
31 #define SWITCH_STBODY 0x04 //Обработано тело case
32 #define SWITCH_STDEFAULT 0x08 //Обработан default
33 plexem STDCALL c_switch( plexem curlex )
34 {
35 uint state; //Текущее состояние функции SWITCH_*
36
37 uint jmpnext;// Ссылка переход на следующий case
38 uint jmpbody;// Cсылка переход на начало блока
39 uint jmpend; // Ссылка переход на конец
40
41 pvmfunc pfunc; //Указатель на структуру операции ==
42 uint parsc[4]; //Параметры для получения кода операции ==
43 uint ltype; //Тип левой части выражения
44 uint dwsize; //Размер типа левой части выражения
45
46 //Инициализация
47 state = SWITCH_STFIRST;
48 jmpnext = -1;
49 jmpbody = -1;
50 jmpend = -1;
51 D( "Switch start\n" );
52
53 //Значение выражения
54 curlex = f_expr( curlex, EXPR_NONULL, <ype, &parsc[1] );
55 parsc[0] = ltype;
56 dwsize = (( povmtype )PCMD( ltype ))->stsize; //Получаем размер типа левой части выражения
57
58 //Главный блок switch
59 curlex = lexem_next( curlex, LEXNEXT_SKIPLINE );
60 if ( curlex->type != LEXEM_OPER ||
61 curlex->oper.operid != OpLcrbrack )//Открывающая фигурная скобка
62 msg( MLcurly | MSG_LEXERR, curlex );// Ошибка Ожадается открывающая фигурная скобка
63 //Главный цикл
64 while ( 1 )
65 {
66 if ( jmpnext != -1 )
67 {
68 //Корректировка последнего перехода
69 j_correct( jmpnext, j_label( LABT_LABELVIRT, -1) );
70 jmpnext = -1;
71 }
72 curlex = lexem_next( curlex, LEXNEXT_IGNLINE );
73 if ( !(state & SWITCH_STDEFAULT ) && curlex->type == LEXEM_KEYWORD )
74 {
75 switch ( curlex->key )
76 {
77 case KEY_CASE:
78 D( "Case\n" );
79 curlex = lexem_next( curlex, 0 );
80 //Цикл проверок условий для текущего Case
81 while ( 1 )
82 { //Удаление из стэка результата сравнения
83 if ( !( state & SWITCH_STFIRST ) &&
84 !( state & SWITCH_STCASE ))
85 out_adduint( CPop );
86
87 state = SWITCH_STCASE;
88 // Добавляем в стэк команду дублирования последнего значения
89 out_adduint( dwsize == 1 ? CDup : CDuplong );
90
91 //Обрабатываем условие
92 curlex = f_expr( curlex, EXPR_COMMA | EXPR_NONULL, &parsc[2], &parsc[3]);
93
94 //Получаем операцию равенства
95 pfunc = bc_funcname( curlex, "#==", 2, parsc );
96 out_adduint( pfunc->vmo.id );
97 if ( (( povmtype )PCMD( pfunc->ret->type ))->stsize == 2 )
98 out_adduint( CLoglongtrue );
99
100 if ( curlex->type == LEXEM_OPER && curlex->oper.operid == OpComma )
101 {
102 D( "Comma\n" );
103 curlex = lexem_next( curlex, LEXNEXT_IGNLINE );
104 }
105 else
106 {
107 //Устанавливаем переход на следующий Case
108 jmpnext = j_jump( CIfznocls, LABT_GTVIRT, -1 );
109 break;
110 }
111 //Устанавливаем переход на тело текущего Case
112 jmpbody = j_jump( CIfnznocls, LABT_GTVIRT, jmpbody );
113 }
114 state = SWITCH_STBODY;
115 //Корректировка меток на текущее тело
116 j_correct( jmpbody, j_label( LABT_LABELVIRT, -1) );
117 jmpbody = -1;
118
119 //Цикл обработки дополнительных меток
120 curlex = lexem_next( curlex, LEXNEXT_SKIPLINE );
121 while ( curlex->type == LEXEM_KEYWORD && curlex->key == KEY_LABEL )
122 {
123 curlex = lexem_next( curlex, 0 );
124 curlex = c_label( curlex );
125 curlex = lexem_next( curlex, LEXNEXT_SKIPLINE );
126 }
127 //Обработка тела
128 curlex = f_body( curlex );
129 //Перход на конец
130 jmpend = j_jump( CGoto, LABT_GTVIRT, jmpend );
131 break;
132
133 case KEY_DEFAULT:
134 //Корректировка последнего перехода
135 state = SWITCH_STDEFAULT;
136 //Цикл обработки дополнительных меток
137 while ( 1 )
138 {
139 curlex = lexem_next( curlex, LEXNEXT_IGNLINE );
140 if ( curlex->type == LEXEM_KEYWORD && curlex->key == KEY_LABEL )
141 curlex = c_label( curlex );
142 else
143 break;
144 }
145 curlex = f_body( curlex );
146 break;
147 default:
148 msg( MNokeyword | MSG_LEXERR, curlex );// Ошибка Неправильное использование ключевого слова
149 }
150 continue;
151 }
152 else
153 {
154 if ( curlex->type == LEXEM_OPER && curlex->oper.operid == OpRcrbrack )
155 {
156 //Корректировка переходов на конец
157 j_correct( jmpend, j_label( LABT_LABELVIRT, -1) );
158 break;//Выйти из тела switch
159 }
160 msg( MRcurly | MSG_LEXERR, curlex );// Ошибка Ожадается закрывающая фигурная скобка
161 }
162 }
163
164 D( "Switch stop\n" );
165 return curlex;
166 }