1 /*      Copyright (C) 2002 Guillaume Bour
2  *
3  *      This program is free software; you can redistribute it and/or modify
4  *      it under the terms of the GNU General Public License as published by
5  *      the Free Software Foundation; either version 2 of the License, or
6  *      (at your option) any later version.
7  *
8  *      This program is distributed in the hope that it will be useful,
9  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *      GNU General Public License for more details.
12  *
13  *      You should have received a copy of the GNU General Public License
14  *      along with this program; if not, write to the Free Software
15  *      Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16  *      MA 02111-1307, USA.
17  */
18 /*
19   FIXME:
20     + on ne peut pas comparer 2 bool�ens (vrai = vrai)
21     + on ne peut pas comparer 2 chaines  ("a = "a)
22  */
23   %{
24     #include <stdio.h>
25     #include <gtk/gtk.h>
26     #include "turtle.h"
27     #include "mc.h"
28     #include "op.h"
29     #include "list.h"
30     #include "constant.h"
31     #include "variable.h"
32 
33     void yyerror(char *error);
34 
35     guint linecnt;
36     gchar *input_str;
37     guint curpos;
38 
39     extern struct s_turtle my_turtle;
40 
41     typedef int(*lexlang_t)(void);
42     lexlang_t lexlang[2] = {
43       enlex,
44       frlex
45     };
46 
47     GSList *repeat_instr = NULL;
48     guint loop_ref;
49 
50     char *lextxt;
51   %}
52 
53 %union {
54   guint intval;
55   gdouble floatval;
56   gboolean boolval;
57   gchar *strval;
58 
59   GSList *list;
60   struct s_class *mc;
61 }
62 
63 %token            TOK_BEGPROC      TOK_ENDPROC
64 %token <strval>   TOK_PROCNAME     TOK_VARIABLE
65 %token            TOK_MOVEFORWARD  TOK_MOVEBACK
66 %token            TOK_TURNRIGHT    TOK_TURNLEFT
67 %token            TOK_SETPOS       TOK_SETHEADING
68 %token            TOK_CLEARSCREEN
69 %token            TOK_HIDETURTLE   TOK_SHOWTURTLE
70 %token            TOK_COLOR
71 %token            TOK_NOTRACE      TOK_TRACE
72 %token            TOK_WRITE        TOK_STOP
73 %token            TOK_RETURN
74 %token            TOK_AFFECT       TOK_LOCALAFFECT
75 %token            TOK_DANCE        TOK_SLEEP
76 
77 %token            TOK_REPEAT       TOK_IF
78 %token            TOK_WHILE
79 
80 %token <intval>   TOK_INT
81 %token <floatval> TOK_FLOAT
82 %token <boolval>  TOK_BOOL
83 %token <strval>   TOK_STRING
84 %token            TOK_LOOPCNT      TOK_HAZARD
85 %token            TOK_GETHEADING
86 
87 %type  <list>     arguments
88 %type  <mc>       arith_expr       bool_expr
89 %type  <mc>       expression
90 
91 %token            TOK_LEQ          TOK_GEQ
92 
93 
94 %left '+' '-'
95 %left '*' '/'
96 %left uneg
97 %left '(' ')'
98 %%
99 
100 input:         procedures statements
101 ;
102 
103 procedures:
104              | procedure procedures
105 ;
106 
107 procedure:     TOK_BEGPROC TOK_PROCNAME
108                  { mc_beginning_procedure($2); }
109                parameters statements TOK_ENDPROC
110                  { mc_ending_procedure(); }
111 ;
112 
113 parameters:
114              | TOK_VARIABLE
115                  { mc_add_proc_parameter($1); }
116                parameters
117 ;
118 
119 statements:
120              | statement statements
121 ;
122 
123 statement:     proc_call
124              | repeat_expr
125              | if_expr
126              | while_expr
127 
128              | TOK_MOVEFORWARD arith_expr
129                  { mc_add_unary_op(OP_MOVEFORWARD, $2); }
130              | TOK_MOVEBACK    arith_expr
131                  { mc_add_unary_op(OP_MOVEBACK, $2); }
132              | TOK_TURNRIGHT   arith_expr
133                  { mc_add_unary_op(OP_TURNRIGHT, $2); }
134              | TOK_TURNLEFT    arith_expr
135                  { mc_add_unary_op(OP_TURNLEFT, $2); }
136              | TOK_SETPOS      '[' arith_expr arith_expr ']'
137                  { mc_add_binary_op(OP_SETPOS, $3, $4); }
138              | TOK_SETHEADING  arith_expr
139                  { mc_add_unary_op(OP_SETHEADING, $2); }
140              | TOK_CLEARSCREEN
141                  { mc_add_noarg_op(OP_CLEARSCREEN); }
142              | TOK_HIDETURTLE
143                  { mc_add_noarg_op(OP_HIDETURTLE); }
144              | TOK_SHOWTURTLE
145                  { mc_add_noarg_op(OP_SHOWTURTLE); }
146              //v�rifier que l'interval est OK (0 � 15) => � l'exec
147              | TOK_COLOR arith_expr
148                  { mc_add_unary_op(OP_SETPREDEFCOLOR, $2); }
149              //v�rifier que l'interval est OK (0 � 255) => � l'exec
150              | TOK_COLOR '[' arith_expr arith_expr arith_expr ']'
151                  {
152 		   GSList *colors = NULL;
153 		   struct s_list *mccolors;
154 
155 		   colors = g_slist_append(colors, $3);
156 		   colors = g_slist_append(colors, $4);
157 		   colors = g_slist_append(colors, $5);
158 
159 		   mccolors = list_alloc(class_free_from_list);
160 		   mccolors->GTKList = colors;
161 
162 		   mc_add_unary_op(OP_SETUSERDEFCOLOR, mccolors);
163 		 }
164              | TOK_NOTRACE
165                  { mc_add_noarg_op(OP_NOTRACE); }
166              | TOK_TRACE
167                  { mc_add_noarg_op(OP_TRACE); }
168              | TOK_WRITE       expression
169                  { mc_add_unary_op(OP_WRITE, $2); }
170              | TOK_STOP
171                  { mc_add_noarg_op(OP_STOP); }
172              | TOK_RETURN      expression
173                  { mc_add_unary_op(OP_RETURN, $2); }
174              | TOK_AFFECT      TOK_STRING
175                  { $<mc>$ = mc_add_variable(VAR_GLOBAL, $2); }
176 	       expression
177                  { mc_add_binary_op(OP_AFFECT, $<mc>3, $4); }
178              | TOK_LOCALAFFECT TOK_STRING
179                  { $<mc>$ = mc_add_variable(VAR_LOCAL, $2); }
180                expression
181                  { mc_add_binary_op(OP_LOCAFFECT, $<mc>3, $4); }
182 
183              | TOK_DANCE
184                  { mc_add_noarg_op(OP_DANCE); }
185              | TOK_SLEEP
186                  { mc_add_noarg_op(OP_SLEEP); }
187 ;
188 
189 proc_call:     TOK_PROCNAME
190                  {
191 		   /* we get the pointer onto the procedure (by its name) */
192 		   $<mc>$ = mc_find_procedure($1);
193 		 }
194                arguments
195                  {
196 		   struct s_list *plist = NULL;
197 
198 		   if($3 != NULL)
199 		     {
200 		       plist = list_alloc(class_free_from_list);
201 		       plist->GTKList = $3;
202 		     }
203 
204 		   //~~~
205 		   mc_add_binary_op(OP_PROCCALL, $<mc>2, plist);
206 		 }
207 ;
208 
209 arguments:       { $$ = NULL; }
210              | expression arguments
211                  { if($1 != NULL) class_ref($1); $$ = g_slist_prepend($2, $1); }
212 ;
213 
214 repeat_expr:   TOK_REPEAT
215                  { $<mc>$ = mc_add_noarg_op(OP_NOOP); }
216                arith_expr
217                  {
218 		   /* warning: the condition is the third argument !! */
219 		   $<mc>$ = mc_add_binary_op(OP_REPEAT, NULL, $3);
220 		   repeat_instr = g_slist_prepend(repeat_instr, $<mc>$);
221 		   loop_ref = 0;
222 		 }
223               '[' statements ']'
224                  {
225 		   struct s_class *jmp, *noop;
226 
227 		   jmp = mc_add_unary_op(OP_JUMP, NULL);
228 		   mc_update_branch(INSTR(jmp),
229 				    INSTR($<mc>2));
230 
231 		   noop = mc_add_noarg_op(OP_NOOP);
232 		   mc_update_branch((struct s_instr *)$<mc>4,
233 				    (struct s_instr *)noop);
234 
235 		   repeat_instr = g_slist_remove(repeat_instr, $<mc>4);
236 		 }
237 ;
238 
239 if_expr:       TOK_IF bool_expr
240                  { $<mc>$ = mc_add_binary_op(OP_IF, NULL, $2); }
241                '['  statements ']'
242                  {
243 		   struct s_class *noop;
244 
245 		   $<mc>$ = mc_add_unary_op(OP_JUMP, NULL);
246 
247 		   noop = mc_add_noarg_op(OP_NOOP);
248 		   mc_update_branch(INSTR($<mc>3),
249 				    INSTR(noop));
250 		 }
251                else_expr
252                  {
253 		   struct s_class *noop;
254 
255 		   noop = mc_add_noarg_op(OP_NOOP);
256 		   mc_update_branch(INSTR($<mc>7),
257 				    INSTR(noop));
258 		 }
259 ;
260 
261 else_expr:
262              | '[' statements ']'
263 ;
264 
265 while_expr:    TOK_WHILE
266                  { $<mc>$ = mc_add_noarg_op(OP_NOOP); }
267                bool_expr
268                  {
269 		   /* warning: the condition is the third argument !! */
270 		   $<mc>$ = mc_add_binary_op(OP_WHILE, NULL, $3);
271 		 }
272                '[' statements ']'
273                  {
274 		   struct s_class *jmp, *noop;
275 
276 		   jmp = mc_add_unary_op(OP_JUMP, NULL);
277 		   mc_update_branch(INSTR(jmp),
278 				    INSTR($<mc>2));
279 
280 		   noop = mc_add_noarg_op(OP_NOOP);
281 		   mc_update_branch(INSTR($<mc>4),
282 				    INSTR(noop));
283 
284 		 }
285 ;
286 
287 expression:    TOK_STRING
288                  { $$ = mc_add_constant(T_STRING, $1); }
289              | bool_expr
290                  { $$ = $1; }
291              | arith_expr
292                  { $$ = $1; }
293 ;
294 
295 bool_expr:     TOK_BOOL
296                  { $$ = mc_add_constant(T_BOOL, $1); }
297 
298              | bool_expr '&' bool_expr
299                  { $$ = mc_add_binary_op(OP_AND, $1, $3); }
300              | bool_expr '|' bool_expr
301                  { $$ = mc_add_binary_op(OP_OR, $1, $3); }
302 
303              | arith_expr '=' arith_expr
304                  { $$ = mc_add_binary_op(OP_EQ, $1, $3); }
305              | arith_expr '<' arith_expr
306                  { $$ = mc_add_binary_op(OP_LT, $1, $3); }
307              | arith_expr '>' arith_expr
308                  { $$ = mc_add_binary_op(OP_GT, $1, $3); }
309              | arith_expr TOK_LEQ arith_expr
310                  { $$ = mc_add_binary_op(OP_LEQ, $1, $3); }
311              | arith_expr TOK_GEQ arith_expr
312                  { $$ = mc_add_binary_op(OP_GEQ, $1, $3); }
313 ;
314 
315 arith_expr:    TOK_INT
316                  { $$ = mc_add_constant(T_INT, $1); }
317              | TOK_FLOAT
318                  { $$ = mc_add_constant(T_FLOAT, $1); }
319              | TOK_VARIABLE
320                  { $$ = mc_add_variable_reference($1); }
321              | TOK_LOOPCNT
322                  {
323 		   struct s_class *repeat;
324 		   /* we must get the reference to the loop counter !!! */
325 		   loop_ref++;
326 		   repeat = g_slist_nth_data(repeat_instr, 0);
327 		   $$ = mc_add_unary_op(OP_LOOPCNT, repeat);
328 		 }
329              | TOK_HAZARD     arith_expr
330                  { $$ = mc_add_unary_op(OP_HAZARD, $2); }
331              | TOK_GETHEADING
332                  { $$ = mc_add_noarg_op(OP_GETHEADING); }
333 
334              | arith_expr '+' arith_expr
335                  { $$ = mc_add_binary_op(OP_ADD, $1, $3); }
336              | arith_expr '-' arith_expr
337                  { $$ = mc_add_binary_op(OP_SUB, $1, $3); }
338              | arith_expr '*' arith_expr
339                  { $$ = mc_add_binary_op(OP_MUL, $1, $3); }
340              | arith_expr '/' arith_expr
341                  { $$ = mc_add_binary_op(OP_DIV, $1, $3); }
342              | '-' arith_expr %prec uneg
343                  { $$ = mc_add_unary_op(OP_UNEG, $2); }
344              | '(' arith_expr ')'
345                  { $$ = $2; }
346 ;
347 %%
348 
349 int  launch_parser(gchar *program)
350 {
351   input_str = program;
352   curpos = 0;
353   linecnt = 0;
354 
355   my_turtle.compilation_failed = FALSE;
356   yyparse();
357 
358   return(0);
359 }
360 
yyerror(char * error)361 void yyerror(char *error)
362 {
363   my_turtle.compilation_failed = TRUE;
364   printf("%d: invalid logo code: '%s'\n", linecnt, lextxt);
365 }
366 
367 /* here we switch between differents languages-parser */
yylex()368 int yylex()
369 {
370   return((*lexlang[my_turtle.locale])());
371 }
372