]> mj.ucw.cz Git - moe.git/blob - judge/token.c
Basic functions for building of judges.
[moe.git] / judge / token.c
1 /*
2  *      Tokenizer for judges
3  *
4  *      (c) 2007 Martin Mares <mj@ucw.cz>
5  */
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include <limits.h>
10 #include <errno.h>
11
12 #include "judge.h"
13
14 #define DEFAULT_MAX_TOKEN (32 << 20)
15
16 void tok_init(struct tokenizer *t, struct stream *s)
17 {
18   memset(t, 0, sizeof(*t));
19   t->stream = s;
20   t->bufsize = 256;
21   t->token = xmalloc(t->bufsize);
22   t->maxsize = DEFAULT_MAX_TOKEN;
23   t->line = 1;
24 }
25
26 void tok_cleanup(struct tokenizer *t)
27 {
28   free(t->token);
29 }
30
31 void tok_err(struct tokenizer *t, char *msg)
32 {
33   die("%s:%d: %s", t->stream->name, t->line, msg);
34 }
35
36 static inline int is_white(int c)
37 {
38   return (c == ' ' || c == '\t' || c == '\r' || c == '\n');
39 }
40
41 char *get_token(struct tokenizer *t)
42 {
43   unsigned int len = 0;
44   int c;
45
46   // Skip whitespace
47   do
48     {
49       c = sgetc(t->stream);
50       if (c < 0)
51         return NULL;
52       if (c == '\n')
53         {
54           t->line++;
55           if (t->flags & TF_REPORT_LINES)
56             {
57               t->toksize = 0;
58               t->token[0] = 0;
59               return t->token;
60             }
61         }
62     }
63   while (is_white(c));
64
65   // This is the token itself
66   do
67     {
68       t->token[len++] = c;
69       if (len >= t->bufsize)
70         {
71           if (len >= t->maxsize)
72             tok_err(t, "Token too long");
73           t->bufsize *= 2;
74           if (t->bufsize > t->maxsize)
75             t->bufsize = t->maxsize;
76           t->token = xrealloc(t->token, t->bufsize);
77         }
78       c = sgetc(t->stream);
79     }
80   while (c >= 0 && !is_white(c));
81   if (c >= 0)
82     sungetc(t->stream);
83
84   t->token[len] = 0;
85   t->toksize = len;
86   return t->token;
87 }
88
89 /*
90  *  Parsing functions. They return 1 if successfully parsed, 0 otherwise.
91  */
92
93 #define PARSE(f, ...)                                           \
94         char *end;                                              \
95         errno = 0;                                              \
96         *x = f(t->token, &end, ##__VA_ARGS__);                  \
97         return !(errno || (unsigned char *) end != t->token + t->toksize)
98
99 int to_long(struct tokenizer *t, long int *x)
100 {
101   PARSE(strtol, 10);
102 }
103
104 int to_ulong(struct tokenizer *t, unsigned long int *x)
105 {
106   if (t->token[0] == '-')               // strtoul accepts negative numbers, but we don't
107     return 0;
108   PARSE(strtoul, 10);
109 }
110
111 int to_double(struct tokenizer *t, double *x)
112 {
113   PARSE(strtod);
114 }
115
116 int to_long_double(struct tokenizer *t, long double *x)
117 {
118   PARSE(strtold);
119 }
120
121 int to_int(struct tokenizer *t, int *x)
122 {
123   long int y;
124   if (!to_long(t, &y) || y > LONG_MAX || y < LONG_MIN)
125     return 0;
126   *x = y;
127   return 1;
128 }
129
130 int to_uint(struct tokenizer *t, unsigned int *x)
131 {
132   unsigned long int y;
133   if (!to_ulong(t, &y) || y > ULONG_MAX)
134     return 0;
135   *x = y;
136   return 1;
137 }
138
139 #define GET(fn, type)                                                                   \
140         type get_##fn(struct tokenizer *t)                                              \
141         {                                                                               \
142           type x;                                                                       \
143           if (!get_token(t))                                                            \
144             tok_err(t, "Unexpected end of file");                                       \
145           if (!to_##fn(t, &x))                                                          \
146             tok_err(t, "Expected " #fn);                                                \
147           return x;                                                                     \
148         }
149
150 GET(int, int)
151 GET(uint, unsigned int)
152 GET(long, long int)
153 GET(ulong, unsigned long int)
154 GET(double, double)
155 GET(long_double, long double)