Version bumped to 1.0.0 for the initial release.
[wllib.git] / mop453.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <math.h>
5 #include <limits.h>
6 #include <errno.h>
7 #include "wllib.h"
8
9 #ifdef FOR_X11
10 #include "mop453.xpm" /* Ikona pro X Window System$^{\def\fntmag{\magstep.2}\rm TM}$ */
11 #endif
12
13 #ifndef PI
14 #ifdef M_PI
15 #define PI M_PI
16 #else
17 #define PI 3.14159265358979323846
18 #endif
19 #endif
20
21 typedef long da_num; /* budeme {\I dyna-add}it \type{long}y */
22 #define NEED_DA_POS /* potêebujeme \func{da_putpos}() a \func{da_getpos}() */
23 #include "dyna-add.c" /* modul dynamického pêidávání */
24
25 float curX,curY; /* souêadnice pera */
26 int curA; /* úhel natoçení pera */
27
28 static void draw_seq(void)
29 { /* vykresli posloupnost z~dyna-struktury */
30 long st1; /* první parametr dyna-struktury */
31 int i; /* pomocné */
32         for (;;) { /* pro neomezený poçet dvojic */
33                 i=da_get(&st1); assert(!!i); /* poslední prvek bude 0 */
34                 if (!st1) return; /* ukonçení posloupnosti */
35                 if (st1<0) { /* prvek$<0$ $\Longrightarrow$ dvë çísla */
36 long p1; /* vzdálenost */
37 float k=0/*fake for GCC*/; /* úhel v~radiánech */
38                         i=da_get(&p1); assert(!!i); /* tento parametr také musí existovat */
39                         curX+=p1*sin(k=(float)curA*PI/180); /* îoupni pérem */
40                         wl_line((long)rint(curX*16),(long)rint((curY+=p1*cos(k))*16)); /* táhni! (\dots çáru) */
41                         if ((curA+=st1)<0) curA+=360; /* natoç pero a moùná pêeteç */
42                         }
43                 else { /* opakuj posloupnost */
44 struct da_pos pos; /* zapamatování pozice pro opakování */
45                         da_putpos(&pos); /* pamatuj! */
46                         while (st1--) { /* \var{st1}-krát */
47                                 da_getpos(&pos); /* pro velký ohlas repríza */
48                                 draw_seq(); /* jedem znova posloupnost */
49                                 }
50                         }
51                 }
52 }
53
54 void drawgfx(void)
55 { /* vykresli gfx */
56 long n;
57         da_reset(); /* nainicializuj dyna-struktury na zaçátek */
58         wl_line((long)(curX=0),(long)(curY=0)); /* první bod je z~$(0,0)$ */
59         curA=0; /* natoçení ªna severº */
60         draw_seq(); /* zpracuj top-level posloupnost */
61         assert(!da_get(&n)); /* ujisti se, ùe to bylo vîe */
62 }
63
64 static long get_lex(void)
65 { /* naçti lexikální element a vraï çíslo,
66 çi LONG_MIN pro \sign[ nebo LONG_MAX pro \sign] */
67 int c,isn=0,neg=0; /* naçtený znak, kousek çísla?, záporné? */
68 long n=0; /* sestavované çíslo */
69         for (;;) { /* \dots a v~ùivotë to nikdo nezastaví */
70                 if ((c=getchar())==EOF) iofail(); /* EOF má pêijít v~\func{main}()u */
71                 if (c=='\n'||c=='\t') c=' '; /* white-space */
72                 if (c==' ') {
73                         if (isn) break; /* je-li kousek çísla, potom oddëlovaç */
74                         else continue; /* jinak ignoruj */
75                         }
76                 if (c=='['||c==']') break; /* terminují vùdy */
77                 if (!neg&&c=='-') { neg=1; continue; } /* záporné çíslo? */
78                 if (c<'0'||c>'9') iofailn(EINVAL); /* tady by to jiù mëla být cifra */
79                 isn=1; /* jiù máme kousek çísla */
80                 if (n>LONG_MAX/10) iofailn(ERANGE); /* nevyteçeme? */
81                 n=n*10+c-'0'; /* pêedpoklady: desítková soustava a souvislé kódy cifer */
82                 }
83         if (isn) { /* terminace uprostêed çísla */
84                 if (neg) n=-n; /* negativní numero */
85                 if (n==LONG_MIN||n==LONG_MAX) iofailn(ERANGE); /* check kolize návratových hodnot */
86                 ungetc(c,stdin); /* byla-li to hranatka, bude jeîtë potêeba, white-space se sveze */
87                 }
88         return(isn?n:(c=='['?LONG_MIN:LONG_MAX)); /* çíslo, çi typ hranatky */
89 }
90
91 long p1,p2; /* pro chroustání posloupnosti jsou jako auto-variábly zbyteçnë expensive */
92
93 static void do_seq(void)
94 { /* nachroustej jednu úroveñ posloupnosti */
95         while ((p1=get_lex())!=LONG_MAX) { /* dokud nenarazíî na \sign] */
96                 if (p1==LONG_MIN) iofailn(EINVAL); /* $P_1$ musí být çíslo */
97                 if ((p2=get_lex())==LONG_MAX) iofailn(EINVAL); /* $P_2$ nesmí být \sign] */
98                 if (p2==LONG_MIN) { /* bylo-li $P_2$ \sign[ */
99                         if (p1<=0) iofailn(EINVAL); /* $P_1$ musí být kladné */
100                         da_put(p1); /* uloù kladné çíslo jako opakovaní */
101                         do_seq(); /* rekurzivnë zpracuj opakovanou posloupnost */
102                         }
103                 else { /* budeme kreslit */
104                         p2%=360; if (p2>=0) p2-=360; /* znormalizuj úhel do záporna */
105                         da_put(p2); da_put(p1); /* nejdêív úhel ($P_2$ -- odliîení od opakování),
106 potom délka ($P_1$) */
107                         }
108                 }
109         da_put(0); /* terminátor posloupnosti */
110 }
111
112 int main(int argc,char **argv)
113 {
114 int i;
115         wl_init(&argc,argv,"MOP453"); /* inicializuj gfx */
116         if (get_lex()!=LONG_MIN) iofailn(EINVAL); /* první element musí být \sign[ */
117         do_seq(); /* zpracuj top-level posloupnost */
118         do i=getchar(); while (i==' '||i=='\n'||i=='\t'); /* seùer white-spacy */
119         if (i!=EOF) iofailn(EINVAL); /* musí být EOF, jinak ERROR */
120         wl_done(); /* gfx okno */
121         return(0); /* hotovo */
122 }