Mercurial > repo
comparison interps/c-intercal/src/yuk.c @ 996:859f9b4339e6
<Gregor> tar xf egobot.tar.xz
author | HackBot |
---|---|
date | Sun, 09 Dec 2012 19:30:08 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
995:6883f5911eb7 | 996:859f9b4339e6 |
---|---|
1 /**************************************************************************** | |
2 | |
3 NAME | |
4 yuk.c -- C-INTERCAL debugger and profiler code, linked into programs. | |
5 | |
6 DESCRIPTION | |
7 File linked into programs as a debugger or profiler. | |
8 | |
9 LICENSE TERMS | |
10 Copyright (C) 2006 Alex Smith | |
11 | |
12 This program is free software; you can redistribute it and/or modify | |
13 it under the terms of the GNU General Public License as published by | |
14 the Free Software Foundation; either version 2 of the License, or | |
15 (at your option) any later version. | |
16 | |
17 This program is distributed in the hope that it will be useful, | |
18 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 GNU General Public License for more details. | |
21 | |
22 You should have received a copy of the GNU General Public License | |
23 along with this program; if not, write to the Free Software | |
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
25 | |
26 ****************************************************************************/ | |
27 #include "config.h" /* AIS: Generated by autoconf */ | |
28 #include <stdlib.h> | |
29 #include <stdio.h> | |
30 #ifdef HAVE_SYS_TIME_H | |
31 # include <sys/time.h> | |
32 # ifdef TIME_WITH_SYS_TIME | |
33 # include <time.h> | |
34 # endif | |
35 #else | |
36 # include <time.h> | |
37 #endif | |
38 #include <signal.h> | |
39 #ifdef HAVE_UNISTD_H | |
40 # include <unistd.h> | |
41 #endif | |
42 #include <setjmp.h> | |
43 #include <string.h> | |
44 | |
45 #define YUKDEBUG 1 | |
46 | |
47 #include "yuk.h" | |
48 #include "ick_lose.h" | |
49 #include "sizes.h" | |
50 #include "abcess.h" | |
51 #include "uncommon.h" | |
52 | |
53 #if YPTIMERTYPE == 4 | |
54 #include <sys/times.h> | |
55 #endif | |
56 | |
57 extern signed char onewatch[]; | |
58 extern signed char twowatch[]; | |
59 extern ick_type16 oneold[]; | |
60 extern ick_type32 twoold[]; | |
61 | |
62 char** globalargv; | |
63 int globalargc; | |
64 int yuklines = 0; | |
65 int yukloop = 0; | |
66 int yukcommands = 0; /* these 5 lines because externs must be defined | |
67 somewhere */ | |
68 /* Global variable storage types: | |
69 static: limited to the file | |
70 unadorned: defining an extern | |
71 extern: defined elsewhere (unless initialised) */ | |
72 | |
73 static char buf[21]; | |
74 | |
75 static sig_atomic_t singlestep = 1; /* if 0, run until a breakpoint */ | |
76 static sig_atomic_t writelines = 1; /* whether to display executed lines onscreen */ | |
77 static int breakpoints[80]; /* initialised to all 0s. Breakpoint locations */ | |
78 static int nbreakpoints = 1; /* how many breakpoints we have */ | |
79 static int monitors[80]; /* monitors give a message when program flow passes them */ | |
80 static int nmonitors = 0; | |
81 static int untilnext = -1; /* NEXTING level to break the program at */ | |
82 static int firstrun = 1; /* ick_first time an interactive command point is reached */ | |
83 static int yukerrcmdg = -1; /* the aboff that indicates an error in the 'g' command */ | |
84 | |
85 static yptimer tickcount; /* yptimer of last run */ | |
86 static int lastaboff = 0; /* last value of aboff */ | |
87 | |
88 static void handlesigint(int i) | |
89 { /* this is a signal handler, so can't do much */ | |
90 singlestep = 1; | |
91 writelines = 1; | |
92 /*@-noeffect@*/ (void) i; /*@=noeffect@*/ | |
93 } | |
94 | |
95 #if YPTIMERTYPE==1 || YPTIMERTYPE==2 | |
96 static yptimer yukgettimeofday() | |
97 { | |
98 static struct timeval tp; | |
99 yptimer temp; | |
100 /* gettimeofday is POSIX; config.sh has checked that it's | |
101 available, so turn off the unrecog warning */ | |
102 /*@-unrecog@*/ | |
103 gettimeofday(&tp,0); | |
104 /*@=unrecog@*/ | |
105 temp=(yptimer)tp.tv_usec + | |
106 (yptimer)tp.tv_sec * (yptimer)1000000LU; | |
107 /* here we make use of unsigned wraparound. In the case | |
108 YPTIMERTYPE == 1, it seems quite likely that we're going | |
109 to wraparound, but because everything is cast to the | |
110 unsigned integral type yptimer, we get a value that will | |
111 wraparound in such a way that - will give us the correct | |
112 time interval. */ | |
113 return temp; | |
114 } | |
115 #elif YPTIMERTYPE == 4 | |
116 yptimer yuktimes() | |
117 { | |
118 static struct tms tp; | |
119 times(&tp); | |
120 return tp.tms_utime + tp.tms_stime; | |
121 } | |
122 #elif YPTIMERTYPE == 5 | |
123 static yptimer yukclock_gettime() | |
124 { | |
125 static struct timespec ts; | |
126 yptimer temp; | |
127 /* We've checked that this function is available; -lrt will be linked in. */ | |
128 /*@-unrecog@*/ | |
129 #if defined(_POSIX_CPUTIME) && _POSIX_CPUTIME > 0 | |
130 clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&ts); | |
131 #else | |
132 # if defined(_POSIX_THREAD_CPUTIME) && _POSIX_THREAD_CPUTIME > 0 | |
133 clock_gettime(CLOCK_THREAD_CPUTIME_ID,&ts); | |
134 # else | |
135 # if defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK > 0 | |
136 clock_gettime(CLOCK_MONOTONIC,&ts); | |
137 # else | |
138 # ifndef CLOCK_REALTIME | |
139 # error clock_gettime is defined, but no clocks seem to be; try changing YPTIMERTYPE in src/yuk.h | |
140 # endif | |
141 clock_gettime(CLOCK_REALTIME,&ts); | |
142 # endif | |
143 # endif | |
144 #endif | |
145 /*@=unrecog@*/ | |
146 temp=(yptimer)ts.tv_nsec + | |
147 (yptimer)ts.tv_sec * (yptimer)1000000000LU; | |
148 /* using wraparound as with gettimeofday */ | |
149 return temp; | |
150 } | |
151 #endif /* YPTIMERTYPE */ | |
152 | |
153 void yukterm(void) | |
154 { | |
155 int i,lastline,thisline,inrow=0; | |
156 yptimer avgtime,avgtime2; | |
157 if(yukopts==2) (void) puts("Program ended without error."); | |
158 if(!(yukopts&1)) return; | |
159 /* Print profiling information */ | |
160 (void) puts("Profiling information saved to \"yuk.out\"."); | |
161 (void) freopen("yuk.out","w",stdout); | |
162 i=-1; | |
163 lastline=-1; | |
164 while(++i<yukcommands) | |
165 { | |
166 thisline=lineofaboff[i]; | |
167 if(thisline==lastline) inrow++; else | |
168 { | |
169 inrow=1; | |
170 printf("%5d:\t%s\n",thisline,textlines[thisline]); | |
171 } | |
172 lastline=thisline; | |
173 avgtime=ypexecount[i]+ypabscount[i]; | |
174 if(avgtime) avgtime=ypexectime[i]/avgtime; | |
175 avgtime2=0; | |
176 if(ypexecount[i]) avgtime2=ypexectime[i]/ypexecount[i]; | |
177 /*@-formatcode@*/ /* Splint doesn't understand string interpolation */ | |
178 printf("C%d: Time%4" YPTIMERTFORMAT ".%0" YPTIMERTFORMATD | |
179 ", Avg%2" YPTIMERTFORMAT ".%0" YPTIMERTFORMATD ", " | |
180 "Avg Exec%2" YPTIMERTFORMAT ".%0" YPTIMERTFORMATD | |
181 ", Exec%8" YPCOUNTERTFORMAT ", Abs%8" YPCOUNTERTFORMAT "\n", | |
182 inrow,ypexectime[i]/YPTIMERSCALE, ypexectime[i]%YPTIMERSCALE, | |
183 avgtime/YPTIMERSCALE, avgtime%YPTIMERSCALE, | |
184 avgtime2/YPTIMERSCALE, avgtime2%YPTIMERSCALE, | |
185 ypexecount[i],ypabscount[i]); | |
186 /*@=formatcode@*/ | |
187 } | |
188 } | |
189 | |
190 void yukline(int aboff,int emitlineno) | |
191 { /* this runs every time a source line is encountered */ | |
192 int i; | |
193 int broken; /* hit a breakpoint, monitorpoint, viewbreak, until */ | |
194 int keeplooping; | |
195 int templine; | |
196 int tempcmd; | |
197 int temp; | |
198 yptimer temptick; | |
199 char* text=textlines[lineofaboff[aboff]]; | |
200 char copyloc[BUFSIZ+9]; | |
201 const char* tempcharp; | |
202 if(!yukopts) return; | |
203 if(globalargc!=3) | |
204 ick_lose(IE778,emitlineno,(const char*)NULL); | |
205 if(yukopts & 1) | |
206 { /* profile */ | |
207 temptick=YPGETTIME; | |
208 if(lastaboff) ypexectime[lastaboff]+=(yptimer)(temptick-tickcount); | |
209 tickcount=temptick; | |
210 if(ick_abstained[aboff]) ypabscount[aboff]++; | |
211 else ypexecount[aboff]++; | |
212 lastaboff=aboff; | |
213 } | |
214 if(yukopts & 2) | |
215 { /* debug */ | |
216 if(firstrun) | |
217 { | |
218 /* GNU GPL requires a copyright notice at this point */ | |
219 (void) puts("yuk debugger Copyright (C) 2006 Alex Smith."); | |
220 (void) puts("The yuk debugger is covered by the GNU GPL and can"); | |
221 (void) puts("be redistributed freely, but comes with ABSOLUTELY"); | |
222 (void) puts("NO WARRANTY. For more information, type *<RET>.\n"); | |
223 (void) puts("For help on yuk, type ?<RET>.\n"); | |
224 } | |
225 i=nbreakpoints; | |
226 broken=0; | |
227 while(i--) broken|=breakpoints[i]==lineofaboff[aboff]; | |
228 if(yukloop&&broken&&*breakpoints!=lineofaboff[aboff]) broken=0; | |
229 if(broken) | |
230 { | |
231 if(*breakpoints!=lineofaboff[aboff]) | |
232 printf("Breakpoint hit at line %d:\n",lineofaboff[aboff]); | |
233 singlestep=1; | |
234 } | |
235 else | |
236 { | |
237 i=nmonitors; | |
238 while(i--) broken|=monitors[i]==lineofaboff[aboff]; | |
239 if(yukloop) broken=0; | |
240 if(broken) printf("Command flowed past line %d:\n",lineofaboff[aboff]); | |
241 } | |
242 if(ick_nextindex <= untilnext) | |
243 { | |
244 broken = 1; | |
245 singlestep = 1; | |
246 } | |
247 if(!broken&&yukerrcmdg==aboff) | |
248 { | |
249 singlestep = 1; | |
250 (void) puts("There are no commands on that line."); | |
251 /* To the user, nothing will have happened but the error message! */ | |
252 } | |
253 i=-1; | |
254 while(++i,1) | |
255 { | |
256 if(yukvars[i].vartype==YUKEND) break; | |
257 if(yukvars[i].vartype==ick_ONESPOT) | |
258 { | |
259 if(onewatch[yukvars[i].intername] != (char)0) | |
260 { | |
261 if(ick_onespots[yukvars[i].intername]!=oneold[yukvars[i].intername]&& | |
262 onewatch[yukvars[i].intername]>(char)1) | |
263 { | |
264 oneold[yukvars[i].intername]=ick_onespots[yukvars[i].intername]; | |
265 if(onewatch[yukvars[i].intername]==(char)2||!ick_onespots[yukvars[i].intername]) | |
266 { | |
267 /*@-formatconst@*/ /* it's safe, I checked it */ | |
268 printf(onewatch[yukvars[i].intername]==(char)2? | |
269 "Variable .%d changed.\n":"Variable .%d became 0.\n", | |
270 yukvars[i].extername); | |
271 /*@=formatconst@*/ | |
272 broken=1; singlestep=1; | |
273 } | |
274 } | |
275 if(writelines||broken) | |
276 { | |
277 printf(".%d is:\n",yukvars[i].extername); | |
278 ick_pout(ick_onespots[yukvars[i].intername]); | |
279 } | |
280 } | |
281 } | |
282 if(yukvars[i].vartype==ick_TWOSPOT) | |
283 { | |
284 if(twowatch[yukvars[i].intername] != (char)0) | |
285 { | |
286 if(ick_twospots[yukvars[i].intername]!=twoold[yukvars[i].intername]&& | |
287 twowatch[yukvars[i].intername] > (char)1) | |
288 { | |
289 twoold[yukvars[i].intername]=ick_twospots[yukvars[i].intername]; | |
290 if(twowatch[yukvars[i].intername]==(char)2||!ick_twospots[yukvars[i].intername]) | |
291 { | |
292 /*@-formatconst@*/ /* there's just the one %d each way round */ | |
293 printf(twowatch[yukvars[i].intername]==(char)2? | |
294 "Variable :%d changed.\n":"Variable :%d became 0.\n", | |
295 yukvars[i].extername); | |
296 /*@=formatconst@*/ | |
297 broken=1; singlestep=1; | |
298 } | |
299 } | |
300 if(writelines||broken) | |
301 { | |
302 printf(":%d is:\n",yukvars[i].extername); | |
303 ick_pout(ick_twospots[yukvars[i].intername]); | |
304 } | |
305 } | |
306 } | |
307 } | |
308 if(writelines||broken) | |
309 { | |
310 /* write line that we're on */ | |
311 printf("%5d:\t%s\n",lineofaboff[aboff],text); | |
312 /* write command within line that we're on */ | |
313 tempcmd=aboff; | |
314 while(tempcmd&&lineofaboff[--tempcmd]==lineofaboff[aboff]); | |
315 printf("On C%d: Abstained %d time%s\n",aboff?aboff-tempcmd:1, | |
316 ick_abstained[aboff]-yukloop,ick_abstained[aboff]-yukloop==1?".":"s."); | |
317 } | |
318 if(singlestep) | |
319 { | |
320 (void)signal(SIGINT,handlesigint); /* placing this line here means that a rapid | |
321 ^C^C will terminate the program, if it's | |
322 stuck in a loop somewhere */ | |
323 keeplooping = 1; | |
324 breakpoints[0] = 0; /* breakpoints[0] goes whenever a breakpoint is hit */ | |
325 untilnext = -1; | |
326 if(yukloop) | |
327 { /* reverse the abstentions that g caused */ | |
328 i = -1; | |
329 while(++i<yukcommands) ick_abstained[i]--; | |
330 } | |
331 yukloop = 0; | |
332 yukerrcmdg = -1; | |
333 do | |
334 { | |
335 printf("yuk007 "); /* this is our prompt, a sort of reverse | |
336 INTERCAL version of % */ | |
337 (void) fgets(buf,20,stdin); | |
338 if(!strchr(buf,'\n')) | |
339 { | |
340 ick_lose(IE810,emitlineno,(const char*)NULL); | |
341 } | |
342 templine=0; | |
343 switch(*buf) | |
344 { | |
345 case '?': | |
346 case '@': | |
347 (void) puts("a<line>\tabstain once from all non-ick_abstained commands on <line>"); | |
348 (void) puts("b<line>\tset breakpoint at <line>"); | |
349 (void) puts("c\tcontinue execution until a breakpoint is reached"); | |
350 (void) puts("d<line>\tdelete breakpoint at <line>"); | |
351 (void) puts("e<line>\texplain the ick_main expression on <line>"); | |
352 (void) puts("f<line>\tstop producing messages when commands on <line> are run"); | |
353 (void) puts("g<line>\tchange currently executing command to the ick_first command"); | |
354 (void) puts("\ton <line> or the ick_next command if already on <line>"); | |
355 (void) puts("h\tlist 10 lines either side of the current line"); | |
356 (void) puts("i<var>\tignore a variable"); | |
357 (void) puts("j<var>\tremember a variable"); | |
358 (void) puts("k\tcontinue until we RESUME back to the current nexting level"); | |
359 (void) puts("\t(that is, step unless we are on a NEXT, in which case execute"); | |
360 (void) puts("\tuntil a RESUME or FORGET back to the same or smaller NEXT stack)"); | |
361 (void) puts("l<line>\tlist 10 lines either side of <line>"); | |
362 (void) puts("m<line>\tproduce a message every time a command on <line> is run"); | |
363 (void) puts("n\tshow the NEXT stack"); | |
364 (void) puts("o\tcontinue until we RESUME/FORGET below the current nexting level"); | |
365 (void) puts("\tie until the NEXT stack becomes smaller than it is at present"); | |
366 (void) puts("p\tdisplay the values of all onespot and twospot variables"); | |
367 (void) puts("q\tabort execution"); | |
368 (void) puts("r<line>\treinstate once all ick_abstained commands on <line>"); | |
369 (void) puts("s\texecute one command"); | |
370 (void) puts("t\tcontinue until a breakpoint, displaying all lines executed"); | |
371 (void) puts("u<line>\texecute until just before <line> is reached"); | |
372 (void) puts("v<var>\tshow value of variable every time a command is printed"); | |
373 (void) puts("w\tshow the current line and current command"); | |
374 (void) puts("x<var>\tremove a variable view, breakchange, or breakzero"); | |
375 (void) puts("y<var>\tview variable every displayed line, and break on change"); | |
376 (void) puts("z<var>\tview variable every displayed line, and break on zero"); | |
377 (void) puts("<var>\tview the value of a onespot or twospot variable"); | |
378 (void) puts("<<var>\tset the value of a onespot or twospot variable"); | |
379 (void) puts("*\tview the GNU General Public License"); | |
380 (void) puts("?\tview this help screen"); | |
381 (void) puts("@\tview this help screen"); | |
382 (void) puts("Line numbers refer to lines of source code, not line labels."); | |
383 (void) puts("Listings have (Axxxxxx) at the start of each line: this shows"); | |
384 (void) puts("the abstention status of each command on that line."); | |
385 (void) puts("The values of variables must be input in proper INTERCAL"); | |
386 (void) puts("notation (i.e. ONE TWO THREE), and are output as butchered"); | |
387 (void) puts("Roman ick_numerals."); | |
388 #ifdef __DJGPP__ | |
389 (void) puts("You can press <CTRL>-<BREAK> to interrupt an executing program."); | |
390 #else | |
391 (void) puts("You can press <CTRL>-C to interrupt an executing program."); | |
392 #endif | |
393 break; | |
394 case 'q': | |
395 exit(0); | |
396 /*@-unreachable@*/ break; /*@=unreachable@*/ | |
397 case 'n': | |
398 i=ick_nextindex; | |
399 if(!i) | |
400 { | |
401 (void) puts("The NEXT stack is empty."); | |
402 } | |
403 else | |
404 { | |
405 (void) puts("Commands NEXTED from:"); | |
406 while(i--) | |
407 { | |
408 /* write NEXT line */ | |
409 printf("%5d:\t%s\n",lineofaboff[ick_next[i]-1], | |
410 textlines[lineofaboff[ick_next[i]-1]]); | |
411 /* write NEXT command within line */ | |
412 tempcmd=(int)ick_next[i]; | |
413 while(tempcmd&&lineofaboff[--tempcmd]==lineofaboff[ick_next[i]-1]); | |
414 printf("NEXTED from command C%u: Abstained %d time%s\n",ick_next[i]-1? | |
415 ick_next[i]-1-tempcmd:1,ick_abstained[ick_next[i]-1], | |
416 ick_abstained[ick_next[i]-1]==1?".":"s."); | |
417 } | |
418 } | |
419 break; | |
420 case 'w': | |
421 /* write line that we're on */ | |
422 printf("%5d:\t%s\n",lineofaboff[aboff],text); | |
423 /* write command within line that we're on */ | |
424 tempcmd=aboff; | |
425 while(tempcmd&&lineofaboff[--tempcmd]==lineofaboff[aboff]); | |
426 printf("On C%d: Abstained %d time%s\n",aboff?aboff-tempcmd:1,ick_abstained[aboff], | |
427 ick_abstained[aboff]==1?".":"s."); | |
428 break; | |
429 case 'p': | |
430 i=-1; | |
431 while(++i,1) | |
432 { | |
433 if(yukvars[i].vartype==YUKEND) break; | |
434 if(yukvars[i].vartype==ick_ONESPOT) | |
435 { | |
436 printf("Variable .%d is:\n",yukvars[i].extername); | |
437 ick_pout(ick_onespots[yukvars[i].intername]); | |
438 } | |
439 if(yukvars[i].vartype==ick_TWOSPOT) | |
440 { | |
441 printf("Variable :%d is:\n",yukvars[i].extername); | |
442 ick_pout(ick_twospots[yukvars[i].intername]); | |
443 } | |
444 } | |
445 break; | |
446 case '.': | |
447 case ':': | |
448 temp = sscanf(buf+1,"%d",&templine); | |
449 if(templine<1 || temp != 1) | |
450 { | |
451 (void) puts("Don't know which variable you mean."); | |
452 break; | |
453 } | |
454 i=-1; | |
455 temp=0; | |
456 while(++i,!temp) | |
457 { | |
458 if(yukvars[i].vartype==YUKEND) break; | |
459 if((*buf=='.'&&yukvars[i].vartype==ick_ONESPOT)|| | |
460 (*buf==':'&&yukvars[i].vartype==ick_TWOSPOT)) | |
461 { | |
462 if(yukvars[i].extername==templine) | |
463 { | |
464 temp=1; | |
465 if(yukvars[i].vartype==ick_ONESPOT) | |
466 { | |
467 ick_pout(ick_onespots[yukvars[i].intername]); | |
468 (void) puts(ick_oneforget[yukvars[i].intername]? | |
469 "This variable is currently ignored.": | |
470 "This variable is currently remembered."); | |
471 } | |
472 if(yukvars[i].vartype==ick_TWOSPOT) | |
473 { | |
474 ick_pout(ick_twospots[yukvars[i].intername]); | |
475 (void) puts(ick_twoforget[yukvars[i].intername]? | |
476 "This variable is currently ignored.": | |
477 "This variable is currently remembered."); | |
478 } | |
479 } | |
480 } | |
481 } | |
482 if(temp) break; | |
483 (void) puts("That variable is not in the program."); | |
484 break; | |
485 case 'v': | |
486 case 'x': | |
487 case 'y': | |
488 case 'z': | |
489 if(buf[1]!='.'&&buf[1]!=':') | |
490 { | |
491 (void) puts("This command only works on onespot and twospot variables."); | |
492 break; | |
493 } | |
494 temp = sscanf(buf+2,"%d",&templine); | |
495 if(templine<1 || temp != 1) | |
496 { | |
497 (void) puts("Don't know which variable you mean."); | |
498 break; | |
499 } | |
500 i=-1; | |
501 temp=0; | |
502 while(++i,!temp) | |
503 { | |
504 if(yukvars[i].vartype==YUKEND) break; | |
505 if(yukvars[i].extername==templine) | |
506 { | |
507 if(buf[1]=='.'&&yukvars[i].vartype==ick_ONESPOT) | |
508 { | |
509 if(*buf=='v') onewatch[yukvars[i].intername]=(char)1; | |
510 if(*buf=='x') onewatch[yukvars[i].intername]=(char)0; | |
511 if(*buf=='y') onewatch[yukvars[i].intername]=(char)2; | |
512 if(*buf=='z') onewatch[yukvars[i].intername]=(char)3; | |
513 oneold[yukvars[i].intername]=ick_onespots[yukvars[i].intername]; | |
514 temp=1; | |
515 } | |
516 if(buf[1]==':'&&yukvars[i].vartype==ick_TWOSPOT) | |
517 { | |
518 if(*buf=='v') twowatch[yukvars[i].intername]=(char)1; | |
519 if(*buf=='x') twowatch[yukvars[i].intername]=(char)0; | |
520 if(*buf=='y') twowatch[yukvars[i].intername]=(char)2; | |
521 if(*buf=='z') twowatch[yukvars[i].intername]=(char)3; | |
522 twoold[yukvars[i].intername]=ick_twospots[yukvars[i].intername]; | |
523 temp=1; | |
524 } | |
525 } | |
526 } | |
527 if(!temp) | |
528 { | |
529 (void) puts("That variable is not in the program."); | |
530 break; | |
531 } | |
532 if(*buf=='v') (void) puts("Set a normal variable view."); | |
533 if(*buf=='x') (void) puts("Removed all views from that variable."); | |
534 if(*buf=='y') (void) puts("Set a breakchange variable view."); | |
535 if(*buf=='z') (void) puts("Set a breakzero variable view."); | |
536 break; | |
537 case 'i': | |
538 case 'j': | |
539 if(buf[1]!='.'&&buf[1]!=':'&&buf[1]!=','&&buf[1]!=';') | |
540 { | |
541 (void) puts("That isn't a real sort of variable."); | |
542 break; | |
543 } | |
544 temp = sscanf(buf+2,"%d",&templine); | |
545 if(templine<1 || temp != 1) | |
546 { | |
547 (void) puts("Don't know which variable you mean."); | |
548 break; | |
549 } | |
550 i=-1; | |
551 temp=0; | |
552 while(++i,!temp) | |
553 { | |
554 if(yukvars[i].vartype==YUKEND) break; | |
555 if((buf[1]=='.'&&yukvars[i].vartype==ick_ONESPOT)|| | |
556 (buf[1]==':'&&yukvars[i].vartype==ick_TWOSPOT)|| | |
557 (buf[1]==','&&yukvars[i].vartype==ick_TAIL)|| | |
558 (buf[1]==';'&&yukvars[i].vartype==ick_HYBRID)) | |
559 { | |
560 if(yukvars[i].extername==templine) | |
561 { | |
562 temp=1; | |
563 if(yukvars[i].vartype==ick_ONESPOT) | |
564 ick_oneforget[yukvars[i].intername]=*buf=='i'; | |
565 if(yukvars[i].vartype==ick_TWOSPOT) | |
566 ick_twoforget[yukvars[i].intername]=*buf=='i'; | |
567 if(yukvars[i].vartype==ick_TAIL) | |
568 ick_tailforget[yukvars[i].intername]=*buf=='i'; | |
569 if(yukvars[i].vartype==ick_HYBRID) | |
570 ick_hyforget[yukvars[i].intername]=*buf=='i'; | |
571 } | |
572 } | |
573 } | |
574 if(temp) | |
575 { | |
576 if(*buf=='i') | |
577 (void) puts("Variable ignored."); | |
578 else | |
579 (void) puts("Variable remembered."); | |
580 break; | |
581 } | |
582 (void) puts("That variable is not in the program."); | |
583 break; | |
584 case '<': | |
585 if(buf[1]!='.'&&buf[1]!=':') | |
586 { | |
587 (void) puts("You cannot set that sort of variable (if it exists at all)."); | |
588 break; | |
589 } | |
590 temp = sscanf(buf+2,"%d",&templine); | |
591 if(templine<1 || temp != 1) | |
592 { | |
593 (void) puts("Don't know which variable you mean."); | |
594 break; | |
595 } | |
596 i=-1; | |
597 temp=0; | |
598 while(++i,!temp) | |
599 { | |
600 if(yukvars[i].vartype==YUKEND) break; | |
601 if((buf[1]=='.'&&yukvars[i].vartype==ick_ONESPOT)|| | |
602 (buf[1]==':'&&yukvars[i].vartype==ick_TWOSPOT)) | |
603 { | |
604 if(yukvars[i].extername==templine) | |
605 { | |
606 temp=1; | |
607 if(yukvars[i].vartype==ick_ONESPOT) | |
608 ick_onespots[yukvars[i].intername]=(ick_type16)ick_pin(); | |
609 if(yukvars[i].vartype==ick_TWOSPOT) | |
610 ick_twospots[yukvars[i].intername]=(ick_type32)ick_pin(); | |
611 /* note that when debugging, you can set an | |
612 ignored variable */ | |
613 } | |
614 } | |
615 } | |
616 if(temp) break; | |
617 (void) puts("That variable is not in the program."); | |
618 break; | |
619 case 'g': | |
620 temp = sscanf(buf+1,"%d",&templine); | |
621 if(!templine || temp != 1) | |
622 { | |
623 (void) puts("Don't know which line you mean."); | |
624 break; | |
625 } | |
626 breakpoints[0] = templine; | |
627 yukloop = 1; | |
628 /* This is implemented by incrementing all ABSTAIN counts, | |
629 even the normally immutable ones on GIVE UP lines, setting | |
630 a temporary breakpoint ([0]) on the line given, and running the | |
631 program. When the breakpoint is hit singlestep will see that | |
632 yukloop is set (its purpose is to cause the program to go back | |
633 to the start when it reaches the end) and decrement all ABSTAIN | |
634 counts, putting the commands back the way they were. We set an error | |
635 breakpoint on this line in case the user is trying to jump to a | |
636 line with no commands (although this debugger command is called | |
637 'g', would I dare to describe this as a GOTO?) */ | |
638 i = -1; | |
639 while(++i<yukcommands) ick_abstained[i]++; | |
640 yukerrcmdg = aboff; | |
641 singlestep = 0; | |
642 writelines = 0; | |
643 keeplooping = 0; /* to break out of the loop in the debugger! */ | |
644 break; | |
645 case 'a': | |
646 case 'r': | |
647 temp = sscanf(buf+1,"%d",&templine); | |
648 if(!templine || temp != 1) | |
649 { | |
650 (void) puts("Don't know which line you mean."); | |
651 break; | |
652 } | |
653 i=-1; | |
654 tempcmd=1; | |
655 while(++i<yukcommands) | |
656 { | |
657 if(lineofaboff[i]==templine) | |
658 { | |
659 temp=ick_abstained[i]; | |
660 if(*buf=='a') if(!temp) ick_abstained[i]=1; | |
661 if(*buf=='r') if(temp) ick_abstained[i]--; | |
662 printf("Command %d on line %d was ick_abstained %d time%s, " | |
663 "now ick_abstained %d time%s.\n",tempcmd,templine, | |
664 temp,temp==1?"":"s",ick_abstained[i], | |
665 ick_abstained[i]==1?"":"s"); | |
666 tempcmd++; | |
667 } | |
668 } | |
669 if(tempcmd==1) (void) puts("No commands start on this line."); | |
670 break; | |
671 case 'k': | |
672 case 'o': | |
673 untilnext=ick_nextindex-(*buf=='o'); | |
674 /*@fallthrough@*/ | |
675 case 'c': | |
676 singlestep=0; | |
677 writelines=0; | |
678 keeplooping=0; | |
679 break; | |
680 case 'b': | |
681 temp = sscanf(buf+1,"%d",&templine); | |
682 if(templine && temp == 1) | |
683 { | |
684 printf("Breakpoint set at line %d.\n",templine); | |
685 breakpoints[nbreakpoints++]=templine; | |
686 if(nbreakpoints>=80) ick_lose(IE811,emitlineno,(const char*)NULL); | |
687 } | |
688 else | |
689 (void) puts("Don't know which line you mean."); | |
690 break; | |
691 case 'd': | |
692 temp = sscanf(buf+1,"%d",&templine); | |
693 if(templine && temp == 1) | |
694 { | |
695 printf("All breakpoints removed from line %d.\n",templine); | |
696 i=nbreakpoints; | |
697 while(i--) if(templine==breakpoints[i]) | |
698 { | |
699 memmove(breakpoints+i,breakpoints+i+1,sizeof(int)*(nbreakpoints-i)); | |
700 nbreakpoints--; | |
701 } | |
702 } | |
703 else | |
704 (void) puts("Don't know which line you mean."); | |
705 break; | |
706 case 'm': | |
707 temp = sscanf(buf+1,"%d",&templine); | |
708 if(templine && temp == 1) | |
709 { | |
710 printf("Monitor set at line %d.\n",templine); | |
711 monitors[nmonitors++]=templine; | |
712 if(nmonitors>=80) ick_lose(IE811,emitlineno,(const char*)NULL); | |
713 } | |
714 else | |
715 (void) puts("Don't know which line you mean."); | |
716 break; | |
717 case 'f': | |
718 temp = sscanf(buf+1,"%d",&templine); | |
719 if(templine && temp == 1) | |
720 { | |
721 printf("All monitors removed from line %d.\n",templine); | |
722 i=nmonitors; | |
723 while(i--) if(templine==monitors[i]) | |
724 { | |
725 memmove(monitors+i,monitors+i+1,sizeof(int)*(nmonitors-i)); | |
726 nmonitors--; | |
727 } | |
728 } | |
729 else | |
730 (void) puts("Don't know which line you mean."); | |
731 break; | |
732 case 's': | |
733 singlestep=1; | |
734 writelines=1; | |
735 keeplooping=0; | |
736 break; | |
737 case 't': | |
738 singlestep=0; | |
739 writelines=1; | |
740 keeplooping=0; | |
741 break; | |
742 case 'u': | |
743 temp = sscanf(buf+1,"%d",&templine); | |
744 if(templine && temp == 1) | |
745 { | |
746 breakpoints[0]=templine; | |
747 singlestep=0; | |
748 writelines=0; | |
749 keeplooping=0; | |
750 } | |
751 else | |
752 (void) puts("Don't know which line you mean."); | |
753 break; | |
754 case 'e': | |
755 temp = sscanf(buf+1,"%d",&templine); | |
756 if(!templine || temp != 1) | |
757 { | |
758 (void) puts("Don't know which line you mean."); | |
759 break; | |
760 } | |
761 tempcmd=-1; | |
762 temp=0; | |
763 i=0; | |
764 while(++tempcmd<yukcommands) | |
765 { | |
766 if(lineofaboff[tempcmd]==templine) | |
767 { | |
768 if(!yukexplain[tempcmd]) ++i; | |
769 else | |
770 { | |
771 printf("C%d: Expression is %s\n",++i,yukexplain[tempcmd]); | |
772 temp++; | |
773 } | |
774 } | |
775 } | |
776 if(!temp) (void) puts("No expressions on that line."); | |
777 break; | |
778 case 'l': | |
779 temp = sscanf(buf+1,"%d",&templine); | |
780 if(!templine || temp != 1) | |
781 { | |
782 (void) puts("Don't know which line you mean."); | |
783 break; | |
784 } | |
785 /*@fallthrough@*/ | |
786 case 'h': | |
787 if(!templine) templine=lineofaboff[aboff]; | |
788 templine-=10; | |
789 if(templine+21>=yuklines) templine=yuklines-22; | |
790 if(templine<1) templine=1; | |
791 i=templine; | |
792 while(i<templine+21&&i<yuklines) | |
793 { | |
794 buf[6]='\0'; | |
795 buf[0]=buf[1]=buf[2]=buf[3]=buf[4]=buf[5]=' '; | |
796 tempcmd=-1; | |
797 temp=0; | |
798 while(++tempcmd<yukcommands) | |
799 { | |
800 if(lineofaboff[tempcmd]==i) | |
801 { | |
802 if(ick_abstained[tempcmd]>9) buf[temp++]='!'; | |
803 else buf[temp++]='0'+(char)ick_abstained[tempcmd]; | |
804 if(temp==6) break; | |
805 } | |
806 } | |
807 printf("(A%s)%5d:\t%s\n",buf,i,textlines[i]); | |
808 i++; | |
809 } | |
810 break; | |
811 case '*': | |
812 tempcharp=ick_findandtestopen("COPYING.txt",globalargv[1], | |
813 "r",globalargv[2]); | |
814 if(tempcharp != NULL) | |
815 { | |
816 #ifndef HAVE_SNPRINTF | |
817 (void) sprintf(copyloc,"more < %s",tempcharp); | |
818 #else | |
819 (void) snprintf(copyloc,sizeof copyloc,"more < %s",tempcharp); | |
820 #endif | |
821 (void) system(copyloc); /* display the GNU GPL copyright */ | |
822 } | |
823 else | |
824 (void) puts("Couldn't find license file. See the file COPYING.txt that\n" | |
825 "came with your C-INTERCAL distribution."); | |
826 break; | |
827 default: | |
828 (void) puts("Not sure what you mean. Try typing ?<RET>."); | |
829 break; | |
830 } | |
831 } while(keeplooping); | |
832 } | |
833 } | |
834 firstrun=0; | |
835 } |