27 static token_type this_token = TOK_NONE;
28 static token_type buffered_token = TOK_NONE;
30 static double token_num;
32 static void NONRET parse_error(const char *msg, ...);
34 static void parse_error(const char *msg, ...)
38 fprintf(stderr, "Parse error: ");
39 vfprintf(stderr, msg, args);
40 fprintf(stderr, "\n");
45 static token_type get_next_token()
47 while (*in_pos == ' ' || *in_pos == '\t' || *in_pos == '\r' || *in_pos == '\n')
54 if (*in_pos >= '0' && *in_pos <= '9' ||
55 *in_pos == '-' && in_pos[1] >= '0' && in_pos[1] <= '9')
58 while (*in_pos >= '0' && *in_pos <= '9' || *in_pos == '.')
62 token_num = stod(token, &end_pos);
63 if (end_pos < token.length())
64 parse_error("Invalid number %s", token.c_str());
68 if (*in_pos >= 'A' && *in_pos <= 'Z' ||
69 *in_pos >= 'a' && *in_pos <= 'z')
71 while (*in_pos >= 'A' && *in_pos <= 'Z' ||
72 *in_pos >= 'a' && *in_pos <= 'z' ||
73 *in_pos >= '0' && *in_pos <= '9')
81 while (*in_pos != '"')
84 parse_error("Unterminated string");
89 parse_error("Unrecognized escape sequence \\%c", *in_pos);
105 return TOK_OPEN_PAREN;
107 return TOK_CLOSE_PAREN;
109 return TOK_OPEN_BRACE;
111 return TOK_CLOSE_BRACE;
113 parse_error("Unrecognized character '%c'", c);
117 static token_type next_token()
119 this_token = get_next_token();
123 static void return_token()
125 assert(this_token != TOK_NONE);
126 assert(buffered_token == TOK_NONE);
127 buffered_token = this_token;
128 this_token = TOK_NONE;
133 static const arg_def move_args[] = {
134 { "x", AT_DIMEN | AT_MANDATORY | AT_POSITIONAL },
135 { "y", AT_DIMEN | AT_MANDATORY | AT_POSITIONAL },
139 static const cmd_def cmd_table[] = {
140 { "move", move_args, NULL },
151 static const unit units[] = {
161 static double parse_dimen(const arg_def *adef)
163 token_type t = next_token();
165 parse_error("Paremeter %s must be a dimension", adef->name);
166 double tmp = token_num;
170 parse_error("Paremeter %s must have a unit", adef->name);
171 for (uint i; units[i].name; i++)
172 if (token == units[i].name)
173 return tmp * units[i].multiplier;
174 parse_error("Unknown unit %s", token.c_str());
177 static cmd_args *parse_args(const cmd_def *cdef)
179 cmd_args *args = new cmd_args;
181 const arg_def *adefs = cdef->arg_defs;
183 while (adefs[num_args].name)
185 args->arg.push_back(arg_val());
186 args->arg_given.push_back(0);
190 token_type t = next_token();
191 if (t != TOK_OPEN_PAREN)
197 bool saw_named = false;
205 while (adefs[argi].name && token != adefs[argi].name)
207 if (!adefs[argi].name)
208 parse_error("Command %s has no parameter %s", cdef->name, token.c_str());
211 parse_error("Parameter name must be followed by '='");
215 parse_error("Positional parameters must precede named ones");
218 while (next_pos < num_args && !(adefs[next_pos].type & AT_POSITIONAL))
220 if (next_pos >= num_args)
221 parse_error("Too many positional arguments for command %s", cdef->name);
225 const arg_def *adef = &adefs[argi];
226 switch (adef->type & AT_TYPE_MASK)
231 parse_error("Paremeter %s must be a string", adef->name);
232 args->arg[argi].s = token;
237 parse_error("Paremeter %s must be a number", adef->name);
238 args->arg[argi].d = token_num;
241 args->arg[argi].d = parse_dimen(adef);
248 if (t == TOK_CLOSE_PAREN)
251 parse_error("Comma expected after parameter %s", adef->name);
257 static cmd *parse_cmd()
259 const cmd_def *cdef = cmd_table;
260 while (cdef->name && token != cdef->name)
263 parse_error("Unknown command %s", token.c_str());
265 cmd_args *args = parse_args(cdef);
268 static void parse(list<cmd> *cmds)
272 token_type t = next_token();
279 cmd *c = parse_cmd();
286 int main(int argc, char **argv)
290 fprintf(stderr, "Usage: pdfjam <commands> <input> <output>\n");