Updated README: Equal sign not required with `--mode` flag.
[sgk-go] / patterns / mkpat.c
CommitLineData
7eeb782e
AT
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
2 * This is GNU Go, a Go program. Contact gnugo@gnu.org, or see *
3 * http://www.gnu.org/software/gnugo/ for more information. *
4 * *
5 * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
6 * 2008 and 2009 by the Free Software Foundation. *
7 * *
8 * This program is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU General Public License as *
10 * published by the Free Software Foundation - version 3 or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License in file COPYING for more details. *
17 * *
18 * You should have received a copy of the GNU General Public *
19 * License along with this program; if not, write to the Free *
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
21 * Boston, MA 02111, USA. *
22\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
23
24/* Compile one of the pattern databases. This takes a database file,
25 * e.g. patterns.db, and produces a C code file, in this case
26 * patterns.c.
27 */
28
29/* See also patterns.h, and the *.db files.
30 */
31
32/* Differences when compiling connections patterns (-c) :
33 * '*' means cutting point
34 * '!' is allowed (inhibit connection there), matches as '.'.
35 * '!' will always be written as the first elements
36*/
37
38/* FIXME: This file is a horrible mess, especially after pattern
39 * matching went 1D. Cleaning it will make future work
40 * with pattern mathing easier.
41 */
42
43/* As in the rest of GNU Go, co-ordinate convention (i,j) is 'i' down from
44 * the top, then 'j' across from the left
45 */
46
47#define USAGE "\
48Usage : mkpat [options] <prefix>\n\
49 General options:\n\
50 -i = one or more input files (typically *.db)\n\
51 -o = output file (typically *.c)\n\
52 -t = DFA transformations file (typically *.dtr)\n\
53 -v = verbose\n\
54 -V <level> = DFA verbiage level\n\
55 Database type:\n\
56 -p = compile general pattern database (the default)\n\
57 -c = compile connections database\n\
58 -C = compile a corner pattern database\n\
59 -D = compile a DFA database (allows fast matching)\n\
60 -d <iterations> = don't generate database, but optimize a DFA\n\
61 transformation file instead\n\
62 Pattern generation options:\n\
63 -O = allow only O to be anchor (the default)\n\
64 -X = allow only X to be anchor\n\
65 -b = allow both colors to be anchor\n\
66 -m = try to place the anchor in the center of the pattern\n\
67 (works best with DFA databases)\n\
68 -a = require anchor in all patterns. Sets fixed_anchor flag in db\n\
69If no input files specified, reads from stdin.\n\
70If output file is not specified, writes to stdout.\n\
71"
72
73
74#ifdef HAVE_CONFIG_H
75#include <config.h>
76#endif
77
78#include <stdio.h>
79#include <stdlib.h>
80#include <string.h>
81#include <ctype.h>
82#include <assert.h>
83
84#include "liberty.h"
85#include "patterns.h"
86#include "gg-getopt.h"
87#include "gg_utils.h"
88
89#include "dfa-mkpat.h"
90
91
92#define DB_GENERAL ((int) 'p')
93#define DB_CONNECTIONS ((int) 'c')
94#define DB_CORNER ((int) 'C')
95#define DB_DFA ((int) 'D')
96#define OPTIMIZE_DFA ((int) 'd')
97
98/* code assumes that ATT_O and ATT_X are 1 and 2 (in either order)
99 * An attribute is a candidate for anchor if (att & anchor) != 0
100 */
101#define ANCHOR_O ATT_O
102#define ANCHOR_X ATT_X
103#define ANCHOR_BOTH (ATT_O | ATT_X)
104
105#define MAXLINE 500
106#define MAXCONSTRAINT 10000
107#define MAXACTION 10000
108#define MAXPATNO 5000
109#define MAXLABELS 20
110#define MAXPARAMS 20
111#define MAX_INPUT_FILE_NAMES 10
112#define MAXNAME 80
113
114/* Avoid compiler warnings with unused parameters */
115#define UNUSED(x) (void)x
116
117/* valid characters that can appear in a pattern
118 * position in string is att value to store
119 */
120static const char VALID_PATTERN_CHARS[] = ".XOxo,a!*?QY";
121static const char VALID_EDGE_CHARS[] = "+-|";
122static const char VALID_CONSTRAINT_LABELS[] = "abcdefghijklmnpqrstuvwyzABCDEFGHIJKLMNPRSTUVWZ";
123
124
125/* the offsets into the list are the ATT_* defined in patterns.h
126 * The following defns are for internal use only, and are not
127 * written out to the compiled pattern database
128 */
129
130#define ATT_star 8
131#define ATT_wild 9
132#define ATT_Q 10
133#define ATT_Y 11
134
135/* These arrays control discarding of unnecessary patval elements.
136 * Modify them using `goal_elements ...' and `callback_data ..'
137 * commands in a database. By default, we don't drop any elements.
138 */
139static int nongoal[8] = {0, 0, 0, 0, 0, 0, 0, 0};
140static int callback_unneeded[8] = {0, 0, 0, 0, 0, 0, 0, 0};
141
142/* stuff used in reading/parsing pattern rows */
143static int maxi, maxj; /* (i,j) offsets of largest element */
144static int mini, minj; /* offset of top-left element
145 (0,0) unless there are edge constraints */
146static int movei, movej;
147static unsigned int where; /* NORTH_EDGE | WEST_EDGE, etc */
148static int el; /* next element number in current pattern */
149static struct patval_b elements[MAX_BOARD*MAX_BOARD]; /* elements of current pattern */
150static int num_stars;
151
152static int ci = -1, cj = -1; /* position of origin (first piece element)
153 relative to top-left */
154static int patno; /* current pattern */
155static int discard_pattern = 0; /* Set to nonzero to discard a pattern (if e.g.
156 * it is too large or duplicated). */
157static int pats_with_constraints = 0; /* just out of interest */
158static int label_coords[256][2]; /* Coordinates for labeled stones in the
159 autohelper patterns. */
160static int current_c_i; /* Counter for the line number of a
161 constraint diagram. */
162static char constraint[MAXCONSTRAINT]; /* Store constraint lines. */
163static char action[MAXCONSTRAINT]; /* Store action lines. */
164static char diagram[MAX_BOARD+2][MAX_BOARD+3];
165 /* store pattern diagram*/
166static char constraint_diagram[MAX_BOARD+2][MAX_BOARD+3];
167 /* store pattern constraint diagram */
168
169/* stuff to maintain info about patterns while reading */
170static char *prefix;
171static struct pattern pattern[MAXPATNO]; /* accumulate the patterns into here */
172static char pattern_names[MAXPATNO][MAXNAME]; /* with optional names here, */
173static int num_attributes;
174static struct pattern_attribute attributes[MAXPATNO * NUM_ATTRIBUTES];
175static char helper_fn_names[MAXPATNO][MAXNAME]; /* helper fn names here */
176static char autohelper_code[MAXPATNO*300]; /* code for automatically generated */
177 /* helper functions here */
178static char *code_pos; /* current position in code buffer */
179struct autohelper_func {
180 const char *name;
181 int params;
182 int type; /* 0 - just copy the parameters,
183 * 1 - add parameter count,
184 * 2 - add address of the current pattern.
185 */
186 float cost;
187 const char *code;
188};
189
190
191/*
192 * current_* are useful for debugging broken patterns.
193 */
194static const char *current_file = NULL;
195static int current_line_number = 0;
196
197
198struct attribute_description {
199 const char *input_name; /* The name used in `.db' files. */
200 enum attribute_type type;
201};
202
203
204static const char *attribute_name[NUM_ATTRIBUTES + 1] = {
205 "MIN_VALUE",
206 "MAX_VALUE",
207 "MIN_TERRITORY",
208 "MAX_TERRITORY",
209 "SHAPE",
210 "FOLLOWUP",
211 "REVERSE_FOLLOWUP",
212 "THREATENS_TO_CAPTURE",
213 "THREATENS_EYE",
214 "REVERSE_SENTE",
215 "LAST_ATTRIBUTE"
216};
217
218
219/* Owl-style value stored in pattern itself. */
220#define IN_PATTERN_VALUE NUM_ATTRIBUTES
221
222static struct attribute_description general_attribute_map[] = {
223 { "value", MIN_VALUE },
224 { "minvalue", MIN_VALUE },
225 { "maxvalue", MAX_VALUE },
226 { "terri", MIN_TERRITORY },
227 { "minterri", MIN_TERRITORY },
228 { "maxterri", MAX_TERRITORY },
229 { "shape", SHAPE },
230 { "followup", FOLLOWUP },
231 { "followup_value", FOLLOWUP },
232 { "reverse_followup", REVERSE_FOLLOWUP },
233 { NULL, LAST_ATTRIBUTE }
234};
235
236static struct attribute_description value_only_attribute_map[] = {
237 { "value", IN_PATTERN_VALUE },
238 { NULL, LAST_ATTRIBUTE }
239};
240
241static struct attribute_description owl_attack_attribute_map[] = {
242 { "value", IN_PATTERN_VALUE },
243 { "threatens_to_capture", THREATENS_TO_CAPTURE },
244 { "threatens_eye", THREATENS_EYE },
245 { "reverse_sente", REVERSE_SENTE },
246 { NULL, LAST_ATTRIBUTE }
247};
248
249static struct attribute_description owl_defense_attribute_map[] = {
250 { "value", IN_PATTERN_VALUE },
251 { "threatens_to_capture", THREATENS_TO_CAPTURE },
252 { "threatens_eye", THREATENS_EYE },
253 { "reverse_sente", REVERSE_SENTE },
254 { NULL, LAST_ATTRIBUTE }
255};
256
257static struct attribute_description *attribute_map = NULL;
258static int attributes_needed = 0;
259
260
261/* ================================================================ */
262/* */
263/* Autohelper function definitions */
264/* */
265/* ================================================================ */
266
267/* Important notice:
268 * If one function has a name which is a prefix of another name, the
269 * shorter name must come later in the list. E.g. "lib" must be preceded
270 * by "lib2", "lib3", and "lib4".
271 */
272static struct autohelper_func autohelper_functions[] = {
273 {"lib2", 1, 0, 0.01, "worm[%s].liberties2"},
274 {"lib3", 1, 0, 0.01, "worm[%s].liberties3"},
275 {"lib4", 1, 0, 0.01, "worm[%s].liberties4"},
276 {"lib", 1, 0, 0.01, "countlib(%s)"},
277 {"alive", 1, 0, 0.01,
278 "(dragon[%s].status == ALIVE)"},
279 {"unknown", 1, 0, 0.01,
280 "(dragon[%s].status == UNKNOWN)"},
281 {"critical", 1, 0, 0.01,
282 "(dragon[%s].status == CRITICAL)"},
283 {"dead", 1, 0, 0.01, "(dragon[%s].status == DEAD)"},
284 {"status", 1, 0, 0.01, "dragon[%s].status"},
285 {"ko", 1, 0, 0.01, "is_ko_point(%s)"},
286 {"xdefend_against", 2, 0, 1.00,
287 "defend_against(%s, OTHER_COLOR(color), %s)"},
288 {"odefend_against", 2, 0, 1.00, "defend_against(%s, color, %s)"},
289 {"defend_against_atari", 1, 0, 1.00,
290 "defend_against_atari_helper(move, %s)"},
291 {"does_defend", 2, 0, 1.00, "does_defend(%s, %s)"},
292 {"does_attack", 2, 0, 1.00, "does_attack(%s, %s)"},
293 {"attack", 1, 0, 1.00, "ATTACK_MACRO(%s)"},
294 {"defend", 1, 0, 1.00, "DEFEND_MACRO(%s)"},
295 {"weakness", 1, 0, 0.01, "dragon_weakness(%s, 0)"},
296 {"weak", 1, 0, 0.01, "dragon_weak(%s)"},
297 {"safe_xmove", 1, 0, 1.00, "safe_move(%s, OTHER_COLOR(color))"},
298 {"safe_omove", 1, 0, 1.00, "safe_move(%s, color)"},
299 {"legal_xmove", 1, 0, 0.05, "is_legal(%s, OTHER_COLOR(color))"},
300 {"legal_omove", 1, 0, 0.05, "is_legal(%s, color)"},
301 {"x_suicide", 1, 0, 0.05, "is_suicide(%s, OTHER_COLOR(color))"},
302 {"o_suicide", 1, 0, 0.05, "is_suicide(%s, color)"},
303 {"x_alive_somewhere", 0, 1, 0.01,
304 "somewhere(OTHER_COLOR(color), 1, %d"},
305 {"o_alive_somewhere", 0, 1, 0.01, "somewhere(color, 1, %d"},
306 {"x_somewhere", 0, 1, 0.01,
307 "somewhere(OTHER_COLOR(color), 0, %d"},
308 {"o_somewhere", 0, 1, 0.01, "somewhere(color, 0, %d"},
309 {"xmoyo_opposite", 1, 0, 0.01,
310 "(whose_moyo(INITIAL_INFLUENCE(color), %s) == OTHER_COLOR(color))"},
311 {"omoyo_opposite", 1, 0, 0.01,
312 "(whose_moyo(INITIAL_INFLUENCE(color), %s) == color)"},
313 {"xmoyo", 1, 0, 0.01,
314 "(whose_moyo(OPPOSITE_INFLUENCE(color), %s) == OTHER_COLOR(color))"},
315 {"omoyo", 1, 0, 0.01,
316 "(whose_moyo(OPPOSITE_INFLUENCE(color), %s) == color)"},
317 {"xarea", 1, 0, 0.01,
318 "(whose_area(OPPOSITE_INFLUENCE(color), %s) == OTHER_COLOR(color))"},
319 {"oarea", 1, 0, 0.01,
320 "(whose_area(OPPOSITE_INFLUENCE(color), %s) == color)"},
321 {"xterri", 1, 0, 0.01,
322 "(whose_territory(OPPOSITE_INFLUENCE(color), %s) == OTHER_COLOR(color))"},
323 {"oterri", 1, 0, 0.01,
324 "(whose_territory(OPPOSITE_INFLUENCE(color), %s) == color)"},
325 {"genus", 1, 0, 0.01, "dragon[%s].genus"},
326 {"approx_xlib", 1, 0, 0.03,
327 "approxlib(%s, OTHER_COLOR(color), MAX_LIBERTIES, NULL)"},
328 {"approx_olib", 1, 0, 0.03,
329 "approxlib(%s, color, MAX_LIBERTIES, NULL)"},
330 {"xlib", 1, 0, 0.05,
331 "accuratelib(%s, OTHER_COLOR(color), MAX_LIBERTIES, NULL)"},
332 {"olib", 1, 0, 0.05,
333 "accuratelib(%s, color, MAX_LIBERTIES, NULL)"},
334 {"xcut", 1, 0, 0.01,
335 "cut_possible(%s, OTHER_COLOR(color))"},
336 {"ocut", 1, 0, 0.05, "cut_possible(%s, color)"},
337 {"edge_double_sente", 4, 1, 3.00,
338 "edge_double_sente_helper(%s, %s, %s, %s)"},
339 {"xplay_defend_both", 2, 1, 3.00,
340 "play_attack_defend2_n(OTHER_COLOR(color), 0, %d"},
341 {"oplay_defend_both", 2, 1, 3.00, "play_attack_defend2_n(color, 0, %d"},
342 {"xplay_attack_either", 2, 1, 3.00,
343 "play_attack_defend2_n(OTHER_COLOR(color), 1, %d"},
344 {"oplay_attack_either", 2, 1, 3.00, "play_attack_defend2_n(color, 1, %d"},
345 {"xplay_defend", 1, 1, 1.00,
346 "play_attack_defend_n(OTHER_COLOR(color), 0, %d"},
347 {"oplay_defend", 1, 1, 1.00, "play_attack_defend_n(color, 0, %d"},
348 {"xplay_attack", 1, 1, 1.00,
349 "play_attack_defend_n(OTHER_COLOR(color), 1, %d"},
350 {"oplay_attack", 1, 1, 1.00, "play_attack_defend_n(color, 1, %d"},
351 {"xplay_break_through", 3, 1, 5.00,
352 "play_break_through_n(OTHER_COLOR(color), %d"},
353 {"oplay_break_through", 3, 1, 5.00, "play_break_through_n(color, %d"},
354 {"oplay_connect", 2, 1, 10.00, "play_connect_n(color, 1, %d"},
355 {"xplay_connect", 2, 1, 10.00,
356 "play_connect_n(OTHER_COLOR(color), 1, %d"},
357 {"oplay_disconnect", 2, 1, 10.00, "play_connect_n(color, 0, %d"},
358 {"xplay_disconnect", 2, 1, 10.00,
359 "play_connect_n(OTHER_COLOR(color), 0, %d"},
360 {"oplay_lib", 1, 1, 0.06, "play_lib_n(color, %d"},
361 {"xplay_lib", 1, 1, 0.06,
362 "play_lib_n(OTHER_COLOR(color), %d"},
363 {"seki_helper", 1, 0, 0.0, "seki_helper(%s)"},
364 {"threaten_to_save", 1, 0, 0.0, "threaten_to_save_helper(move,%s)"},
365 {"threaten_to_capture", 1, 0, 0.0,
366 "threaten_to_capture_helper(move,%s)"},
367 {"prevent_attack_threat", 1, 0, 0.0,
368 "prevent_attack_threat_helper(move, %s)"},
369 {"eye", 1, 0, 0.01, "is_eye_space(%s)"},
370 {"proper_eye", 1, 0, 0.01, "is_proper_eye_space(%s)"},
371 {"marginal_eye", 1, 0, 0.01, "is_marginal_eye_space(%s)"},
372 {"halfeye", 1, 0, 0.01, "is_halfeye(half_eye,%s)"},
373 {"max_eye_value", 1, 0, 0.01, "max_eye_value(%s)"},
374 {"owl_topological_eye", 2, 0, 0.01, "owl_topological_eye(%s, board[%s])"},
375 {"obvious_false_oeye", 1, 0, 0.01, "obvious_false_eye(%s, color)"},
376 {"obvious_false_xeye", 1, 0, 0.01,
377 "obvious_false_eye(%s, OTHER_COLOR(color))"},
378 {"antisuji", 1, 0, 0.0, "add_antisuji_move(%s)"},
379 {"add_connect_move", 2, 0, 0.0, "add_connection_move(move,%s, %s)"},
380 {"add_cut_move", 2, 0, 0.0, "add_cut_move(move, %s, %s)"},
381 {"test_attack_either_move", 2, 0, 0.0,
382 "test_attack_either_move(move, color, %s, %s)"},
383 {"add_defend_both_move", 2, 0, 0.0,
384 "add_all_move(move, DEFEND_STRING, %s, DEFEND_STRING, %s)"},
385 {"same_dragon", 2, 0, 0.01, "is_same_dragon(%s, %s)"},
386 {"same_string", 2, 0, 0.01, "same_string(%s, %s)"},
387 {"dragonsize", 1, 0, 0.01, "dragon[%s].size"},
388 {"wormsize", 1, 0, 0.01, "countstones(%s)"},
389 {"effective_size", 1, 0, 0.01, "dragon[%s].effective_size"},
390 {"vital_chain", 1, 0, 0.05, "vital_chain(%s)"},
391 {"potential_cutstone", 1, 0, 0.01, "worm[%s].cutstone2 > 1"},
392 {"amalgamate_most_valuable_helper", 3, 0, 0.0,
393 "amalgamate_most_valuable_helper(%s, %s, %s)"},
394 {"amalgamate", 2, 0, 0.0, "join_dragons(%s, %s)"},
395 {"owl_escape_value", 1, 0, 0.01, "owl_escape_value(%s)"},
396 {"owl_goal_dragon", 1, 0, 0.01, "owl_goal_dragon(%s)"},
397 {"owl_eyespace", 1, 0, 0.01, "owl_eyespace(%s)"},
398 {"owl_big_eyespace", 1, 0, 0.01, "owl_big_eyespace(%s)"},
399 {"owl_mineye", 1, 0, 0.01, "owl_mineye(%s)"},
400 {"owl_maxeye", 1, 0, 0.01, "owl_maxeye(%s)"},
401 {"owl_proper_eye", 1, 0, 0.01, "owl_proper_eye(%s)"},
402 {"owl_eye_size", 1, 0, 0.01, "owl_eye_size(%s)"},
403 {"owl_lunch", 1, 0, 0.01, "owl_lunch(%s)"},
404 {"owl_strong_dragon", 1, 0, 0.01, "owl_strong_dragon(%s)"},
405 {"has_aji", 1, 0, 0.01,
406 "(dragon[%s].owl_threat_status == CAN_THREATEN_DEFENSE)"},
407 {"finish_ko_helper", 1, 0, 0.05, "finish_ko_helper(%s)"},
408 {"squeeze_ko_helper", 1, 0, 0.03, "squeeze_ko_helper(%s)"},
409 {"backfill_helper", 3, 0, 1.50, "backfill_helper(%s, %s, %s)"},
410 {"connect_and_cut_helper2", 3, 0, 3.00,
411 "connect_and_cut_helper2(%s, %s, %s, color)"},
412 {"connect_and_cut_helper", 3, 0, 3.00, "connect_and_cut_helper(%s, %s, %s)"},
413 {"owl_threatens", 2, 0, 0.01, "owl_threatens_attack(%s, %s)"},
414 {"replace", 2, 0, 0.0, "add_replacement_move(%s, %s, color)"},
415 {"backfill_replace", 2, 0, 0.0, "backfill_replace(%s, %s)"},
416 {"non_oterritory", 1, 0, 0.0,
417 "influence_mark_non_territory(%s, color)"},
418 {"non_xterritory", 1, 0, 0.0,
419 "influence_mark_non_territory(%s, OTHER_COLOR(color))"},
420 {"remaining_handicap_stones", 0, 0, 0.0, "free_handicap_remaining_stones()"},
421 {"total_handicap_stones", 0, 0, 0.0, "free_handicap_total_stones()"},
422 {"o_captures_something", 1, 0, 0.02, "does_capture_something(%s, color)"},
423 {"x_captures_something", 1, 0, 0.02,
424 "does_capture_something(%s, OTHER_COLOR(color))"},
425 {"false_eye_territory", 1, 0, 0.0, "false_eye_territory[%s]"},
426 {"false_eye", 1, 0, 0.01, "is_false_eye(half_eye, %s)"},
427 {"o_visible_along_edge", 2, 0, 0.05, "visible_along_edge(color,%s,%s)"},
428 {"x_visible_along_edge", 2, 0, 0.05,
429 "visible_along_edge(OTHER_COLOR(color),%s,%s)"},
430 {"is_surrounded", 1, 0, 0.01, "is_surrounded(%s)"},
431 {"does_surround", 2, 0, 1.00, "does_surround(%s, %s)"},
432 {"surround_map", 2, 0, 0.01, "surround_map(%s, %s)"},
433 {"oracle_threatens", 2, 0, 0.01, "oracle_threatens(%s, %s)"},
434 {"value", 0, 2, 0.0, "(%s->value)"},
435 {"adjacent_to_stone_in_atari", 1, 0, 1.0,
436 "adjacent_to_stone_in_atari(%s)"},
437 {"adjacent_to_defendable_stone_in_atari", 1, 0, 1.0,
438 "adjacent_to_defendable_stone_in_atari(%s)"},
439 {"good_attack_threat", 2, 0, 0.01, "register_good_attack_threat(%s, %s)"},
440 {"known_safe_move", 1, 0, 0.01, "register_known_safe_move(%s)"},
441 {"break_mirror_helper", 1, 0, 0.01, "break_mirror_helper(%s, color)"}
442};
443
444
445/* To get a valid function pointer different from NULL. */
446static int
447dummyhelper(int transformation, int move, int color, int action)
448{
449 UNUSED(transformation); UNUSED(move); UNUSED(color);
450 UNUSED(action);
451 return 0;
452}
453
454
455#define PREAMBLE "\
456/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\
457 * This is GNU Go, a Go program. Contact gnugo@gnu.org, or see *\n\
458 * http://www.gnu.org/software/gnugo/ for more information. *\n\
459 * *\n\
460 * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *\n\
461 * 2008 and 2009 by the Free Software Foundation. *\n\
462 * *\n\
463 * This program is free software; you can redistribute it and/or *\n\
464 * modify it under the terms of the GNU General Public License as *\n\
465 * published by the Free Software Foundation - version 3 or *\n\
466 * (at your option) any later version. *\n\
467 * *\n\
468 * This program is distributed in the hope that it will be useful, *\n\
469 * but WITHOUT ANY WARRANTY; without even the implied warranty of *\n\
470 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *\n\
471 * GNU General Public License in file COPYING for more details. *\n\
472 * *\n\
473 * You should have received a copy of the GNU General Public *\n\
474 * License along with this program; if not, write to the Free *\n\
475 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *\n\
476 * Boston, MA 02111, USA. *\n\
477 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n\
478#include <stdio.h> /* for NULL */\n\
479#include \"liberty.h\"\n\
480#include \"patterns.h\"\n\n\
481"
482
483static int fatal_errors = 0;
484
485/* options */
486int verbose = 0; /* -v */
487static int database_type = 0; /* -p (default), -c, -f, -C, -D or -T */
488static int anchor = 0; /* Whether both O and/or X may be anchors.
489 * -b for both. -X for only X.
490 */
491
492static int choose_best_anchor = 0; /* -m */
493/* FIXME: `fixed anchor' option doesn't work properly yet.
494 * Probably the first thing to implement is to add
495 * checks for anchor validity.
496 */
497static int fixed_anchor = 0; /* -a */
498
499static dfa_t dfa;
500static dfa_patterns dfa_pats;
501
502static int transformation_hint;
503static int labels_transformation = 0;
504
505
506struct hint_data {
507 char name[MAXNAME];
508 int transformation_hint;
509 struct hint_data *next;
510};
511
512static struct hint_data *first_hint = NULL;
513
514
515static void
516parse_transformations_file(FILE *file)
517{
518 struct hint_data **link = &first_hint;
519
520 while (!feof(file)) {
521 int n;
522 struct hint_data *hint = malloc(sizeof(*hint));
523
524 n = fscanf(file, "%s %d", hint->name, &hint->transformation_hint);
525 if (n == 2) {
526 hint->next = NULL;
527 *link = hint;
528 link = &hint->next;
529 }
530 else
531 free(hint);
532 }
533}
534
535
536static int
537find_transformation_hint(const char *pattern_name)
538{
539 struct hint_data *hint;
540
541 if (database_type == DB_DFA || database_type == OPTIMIZE_DFA) {
542 for (hint = first_hint; hint; hint = hint->next) {
543 if (!strcmp(hint->name, pattern_name))
544 return hint->transformation_hint;
545 }
546 }
547
548 return database_type == OPTIMIZE_DFA ? -1 : 0;
549}
550
551
552/**************************
553 *
554 * stuff to check the constraint diagram
555 *
556 **************************/
557
558#define CHECK_CHARS "xXoO"
559static void
560check_constraint_diagram(void)
561{
562 int i, j, ino = 0, iso = 0, jwo = 0;
563
564 int have_constraint = (pattern[patno].autohelper_flag & HAVE_CONSTRAINT);
565 if (0)
566 fprintf(stderr, "patno: %d\n", patno);
567
568 if (where & NORTH_EDGE)
569 ino = 1;
570 if (where & SOUTH_EDGE)
571 iso = 1;
572 if (where & WEST_EDGE)
573 jwo = 1;
574
575 if (verbose) {
576 for (i = ino; i <= maxi+ino+iso; i++)
577 fprintf(stderr, "%02d %s\n", i, diagram[i]);
578 for (i = ino; i <= maxi+ino+iso; i++)
579 fprintf(stderr, "%02d %s\n", i, constraint_diagram[i]);
580 }
581
582 if (0)
583 fprintf(stderr, "have_constraint: %d\n", have_constraint);
584 if (have_constraint && el) {
585 for (i = ino; i <= maxi+ino; i++)
586 for (j = jwo; j <= maxj+jwo; j++) {
587 if (0)
588 fprintf(stderr, "%2d %2d %c %c\n", i, j, constraint_diagram[i][j],
589 diagram[i][j]);
590 if (strchr(CHECK_CHARS, constraint_diagram[i][j])
591 && constraint_diagram[i][j] != diagram[i][j]) {
592 fprintf(stderr, "%s(%d) : Error : "
593 "xXoO not matched in constraint diagram of pattern %s\n",
594 current_file, current_line_number, pattern_names[patno]);
595 fatal_errors++;
596 }
597 }
598 }
599}
600
601/**************************
602 *
603 * stuff to parse the input
604 *
605 **************************/
606
607/* reset state of all pattern variables */
608static void
609reset_pattern(void)
610{
611 int i, j;
612
613 maxi = 0;
614 maxj = 0;
615 ci = -1;
616 cj = -1;
617 where = 0;
618 el = 0;
619 num_stars = 0;
620 strcpy(helper_fn_names[patno], "NULL");
621 for (i = 0; i < 256; i++)
622 label_coords[i][0] = -1;
623 current_c_i = 0;
624 constraint[0] = 0;
625 action[0] = 0;
626 for (i = 0; i < MAX_BOARD+2; i++) {
627 for (j = 0; j < MAX_BOARD+3; j++) {
628 diagram[i][j] = '\0';
629 constraint_diagram[i][j] = '\0';
630 }
631 }
632 memset(&pattern[patno], 0, sizeof(struct pattern));
633}
634
635
636/* This is called to compute the extents of the pattern, applying
637 * edge constraints as necessary.
638 */
639static void
640find_extents(void)
641{
642 /* When this is called, elements go from (mini,minj) inclusive to
643 * (maxi-1, maxj-1) [ie exclusive]. Make them inclusive.
644 * Ie maximum element lies on (maxi,maxj).
645 */
646
647 --maxi;
648 --maxj;
649
650 /* apply edge constraints to the size of the pattern */
651
652 if (where & (NORTH_EDGE | SOUTH_EDGE | EAST_EDGE | WEST_EDGE))
653 ++pats_with_constraints;
654
655 if (verbose)
656 fprintf(stderr, "Pattern %s has constraints 0x%x\n",
657 pattern_names[patno], where);
658
659 pattern[patno].edge_constraints = where;
660
661
662 /* At this point, (mini,minj) -> (maxi,maxj) contain
663 * the extent of the pattern, relative to top-left
664 * of pattern, rather than (ci,cj).
665 *
666 * But we store them in the output file relative
667 * to (ci,cj), so that we can transform the corners
668 * of the pattern like any other relative co-ord.
669 */
670
671 pattern[patno].mini = mini - ci;
672 pattern[patno].minj = minj - cj;
673 pattern[patno].maxi = maxi - ci;
674 pattern[patno].maxj = maxj - cj;
675}
676
677
678/*
679 * Here we build the dfa.
680 */
681
682static void
683write_to_dfa(int index)
684{
685 char str[DFA_MAX_ORDER + 1];
686 char strrot[DFA_MAX_ORDER + 1];
687
688 assert(ci != -1 && cj != -1);
689#if 0
690 pattern[index].patn = elements; /* a little modification : keep in touch! */
691#endif
692 pattern[index].name = &(pattern_names[index][0]);
693
694 /* First we create the string from the actual pattern. */
695 pattern_2_string(pattern + index, elements, str, ci, cj);
696
697 if (verbose)
698 fprintf(stderr, "Add :%s\n", pattern[index].name);
699
700 if (database_type == DB_DFA) {
701 float ratio;
702
703 dfa_rotate_string(strrot, str, transformation_hint);
704 ratio = ((dfa_add_string(&dfa, strrot, index, transformation_hint) - 1.0)
705 * 100);
706
707 /* Complain when there is more than 10% of increase */
708 if (dfa_size(&dfa) > 100 && ratio > 10.0) {
709 fprintf(stderr, "Pattern %s => %3.1f%% increase: ",
710 pattern[index].name, ratio);
711 fprintf(stderr, "another orientation may save memory.\n");
712 }
713 if (dfa_verbose > 2)
714 dump_dfa(stderr, &dfa);
715
716 labels_transformation = transformation_hint;
717 }
718 else {
719 int ll;
720 int rot_start = 0;
721 int rot_stop = pattern[index].trfno;
722
723 assert(database_type == OPTIMIZE_DFA);
724
725 if (rot_stop == 5) {
726 rot_start = 2;
727 rot_stop = 6;
728 }
729
730 for (ll = rot_start; ll < rot_stop; ll++) {
731 dfa_rotate_string(strrot, str, ll);
732 dfa_patterns_add_pattern(&dfa_pats, strrot, index);
733 }
734
735 if (transformation_hint == -1)
736 dfa_patterns_select_shortest_variation(&dfa_pats);
737 else {
738 dfa_patterns_set_last_pattern_variation(&dfa_pats, (transformation_hint
739 - rot_start));
740 }
741 }
742}
743
744
745/* For good performance, we want to reject patterns as quickly as
746 * possible. For each pattern, this combines 16 positions around
747 * the anchor stone into a 32-bit mask and value. In the matcher,
748 * the same 4x4 grid is precomputed, and then we can quickly
749 * test 16 board positions with one test.
750 * See matchpat.c for details of how this works - basically, if
751 * we AND what is on the board with the and_mask, and get the
752 * value in the val_mask, we have a match. This test can be
753 * applied in parallel : 2 bits per posn x 16 posns = 32 bits.
754 * "Don't care" has and_mask = val_mask = 0, which is handy !
755 */
756
757static void
758compute_grids(void)
759{
760#if GRID_OPT
761 /* element: . X O x o , a ! */
762 static const unsigned int and_mask[] = { 3, 3, 3, 1, 2, 3, 3, 3 };
763 static const unsigned int val_mask[] = { 0, 2, 1, 0, 0, 0, 0, 0 };
764
765 int ll; /* iterate over rotations */
766 int k; /* iterate over elements */
767
768 for (ll = 0; ll < 8; ++ll) {
769 for (k = 0; k < el; ++k) {
770 int ti, tj;
771 int di, dj;
772
773 TRANSFORM2(elements[k].x - ci, elements[k].y - cj, &ti, &tj,
774 transformation_hint);
775 TRANSFORM2(ti, tj, &di, &dj, ll);
776
777 ++di;
778 ++dj;
779 if (di >= 0 && di < 4 && dj >= 0 && dj < 4) {
780 pattern[patno].and_mask[ll]
781 |= and_mask[elements[k].att] << (30 - di * 8 - dj * 2);
782 pattern[patno].val_mask[ll]
783 |= val_mask[elements[k].att] << (30 - di * 8 - dj * 2);
784 }
785 }
786 }
787#endif
788}
789
790
791/* We've just read a line that looks like a pattern line. Now process it.
792 * If the pattern becomes larger than maximal supported board, the function
793 * returns zero, so that the pattern can be discarded.
794 */
795static int
796read_pattern_line(char *p)
797{
798 const char *char_offset;
799 char *pcopy = p;
800 int j;
801 int width;
802 int jwo = 0, jeo = 0;
803
804 if (where & SOUTH_EDGE)
805 /* something wrong here : pattern line after a SOUTH_EDGE constraint */
806 goto fatal;
807
808
809 if (*p == '+' || *p == '-') {
810 /* must be a north/south constraint */
811
812 if (maxi == 0)
813 where |= NORTH_EDGE;
814 else
815 where |= SOUTH_EDGE;
816
817 if (*p == '+') {
818 if (maxi > 0 && !(where & WEST_EDGE))
819 /* if this is end of pattern, must already know about west */
820 goto fatal;
821
822 where |= WEST_EDGE;
823 ++p;
824 }
825
826 /* count the number of -'s */
827 for (width = 0; *p == '-'; ++p, ++width)
828 ;
829
830 if (width == 0)
831 goto fatal;
832
833 if (*p == '+') {
834 if (maxi > 0 && !(where & EAST_EDGE))
835 /* if this is end of pattern, must already know about west */
836 goto fatal;
837 where |= EAST_EDGE;
838 }
839
840 if (maxi > 0 && width != maxj)
841 goto notrectangle;
842
843 return 1;
844 }
845
846 /* get here => its a real pattern entry,
847 * rather than a north/south constraint
848 */
849
850 /* we have a pattern line - add it into the current pattern */
851 if (*p == '|') {
852 /* if this is not the first line, or if there is a north
853 * constraint, we should already know about it
854 */
855 if (!(where & WEST_EDGE) && ((where & NORTH_EDGE) || maxi > 0))
856 /* we should already know about this constraint */
857 goto fatal;
858
859 where |= WEST_EDGE;
860 ++p;
861 }
862 else if (where & WEST_EDGE)
863 /* need a | if we are already constrained to west */
864 goto fatal;
865
866
867 for (j = 0;
868 (char_offset = strchr(VALID_PATTERN_CHARS, *p)) != NULL;
869 ++j, ++p) {
870
871 /* char_offset is a pointer within the VALID_PATTERN_CHARS string.
872 * so (char-VALID_PATTERN_CHARS) is the att (0 to 11) to write to the
873 * pattern element
874 */
875
876 /* one of ATT_* - see above */
877 int off = char_offset - VALID_PATTERN_CHARS;
878
879 if (off == ATT_wild)
880 continue; /* boring - pad character */
881
882 if (off == ATT_a) /* this were used by halfeye patterns */
883 goto fatal;
884
885 if (off == ATT_star) {
886 /* '*' */
887 movei = maxi;
888 movej = j;
889 ++num_stars;
890 off = ATT_dot; /* add a '.' to the pattern instead */
891 }
892
893 if (off == ATT_Q) {
894 off = ATT_O;
895 ci = maxi;
896 cj = j;
897 pattern[patno].anchored_at_X = (off == ATT_X) ? 3 : 0;
898 /*FIXME: Make sure O is valid anchor*/
899 }
900
901 if (off == ATT_Y) {
902 off = ATT_X;
903 ci = maxi;
904 cj = j;
905 pattern[patno].anchored_at_X = (off == ATT_X) ? 3 : 0;
906 /*FIXME: Make sure X is valid anchor*/
907 }
908
909 assert(off <= ATT_not);
910
911
912 if ((ci == -1) && (off < 3) && ((off & anchor) != 0)
913 && !fixed_anchor) {
914 /* Use this position as the pattern origin. */
915 ci = maxi;
916 cj = j;
917 pattern[patno].anchored_at_X = (off == ATT_X) ? 3 : 0;
918 }
919
920 /* Range checking. */
921 if (el >= (int) (sizeof(elements) / sizeof(elements[0])))
922 return 0;
923
924 elements[el].x = maxi;
925 elements[el].y = j;
926 elements[el].att = off; /* '*' mapped to '.' and 'Q' to 'O' above */
927
928 ++el;
929 }
930
931 if (*p == '|') {
932
933 /* if this is not the first line, or if there is a north
934 * constraint, we should already know about it
935 */
936 if (!(where & EAST_EDGE) && ((where & NORTH_EDGE) || maxi > 0))
937 goto fatal; /* we should already know about this constraint */
938
939 where |= EAST_EDGE;
940
941 }
942 else if (where & EAST_EDGE)
943 goto fatal; /* need a | if we are already constrained to east */
944
945
946 if (maxi > 0 && j != maxj)
947 goto notrectangle;
948
949 if (j > maxj)
950 maxj = j;
951
952
953 if (where & WEST_EDGE)
954 jwo = 1;
955 if (where & EAST_EDGE)
956 jeo = 1;
957 if (maxi <= MAX_BOARD)
958 strncpy(diagram[maxi], pcopy, maxj + jwo + jeo);
959 maxi++;
960
961 return maxi <= MAX_BOARD && maxj <= MAX_BOARD;
962
963fatal:
964 fprintf(stderr, "%s(%d) : error : Illegal pattern %s\n",
965 current_file, current_line_number, pattern_names[patno]);
966 fatal_errors = 1;
967 return 0;
968
969notrectangle:
970 fprintf(stderr, "%s(%d) : error : Pattern %s not rectangular\n",
971 current_file, current_line_number, pattern_names[patno]);
972 fatal_errors++;
973 return 0;
974}
975
976
977/*
978 * We've just read a line that looks like a constraint pattern line.
979 * Now process it.
980 */
981
982static void
983read_constraint_diagram_line(char *p)
984{
985 int j;
986 int jwo = 0, jeo = 0;
987 const char *pcopy = p;
988
989 /* North or south boundary, no letter to be found. */
990 if (*p == '+' || *p == '-')
991 return;
992
993 /* Skip west boundary. */
994 if (*p == '|')
995 p++;
996
997 for (j = 0;
998 strchr(VALID_PATTERN_CHARS, *p) || strchr(VALID_CONSTRAINT_LABELS, *p);
999 ++j, ++p) {
1000 if (strchr(VALID_CONSTRAINT_LABELS, *p)
1001 && label_coords[(int)*p][0] == -1) {
1002
1003 /* New constraint letter */
1004 label_coords[(int)*p][0] = current_c_i;
1005 label_coords[(int)*p][1] = j;
1006 }
1007 }
1008
1009 /* Now j holds the width of this constraint diagram line. Require
1010 * this to match the main diagram width stored in maxj. However,
1011 * maxj was modified by find_extents() so we have to compensate for
1012 * this.
1013 */
1014 if (j != maxj + 1 && !discard_pattern) {
1015 fprintf(stderr, "%s(%d) : error : Mismatching width of constraint line in pattern %s\n",
1016 current_file, current_line_number, pattern_names[patno]);
1017 fatal_errors++;
1018 return;
1019 }
1020
1021 if (where & WEST_EDGE)
1022 jwo = 1;
1023 if (where & EAST_EDGE)
1024 jeo = 1;
1025 if (el)
1026 strncpy(constraint_diagram[current_c_i], pcopy, maxj+jwo+jeo+1);
1027 current_c_i++;
1028
1029 return;
1030}
1031
1032/* Check that the constraint diagram had the same number of rows as
1033 * the main diagram.
1034 */
1035static void
1036check_constraint_diagram_size(void)
1037{
1038 if (current_c_i != maxi + 1 && !discard_pattern) {
1039 fprintf(stderr, "%s(%d) : error : Mismatching height of constraint diagram in pattern %s\n",
1040 current_file, current_line_number, pattern_names[patno]);
1041 fatal_errors++;
1042 }
1043}
1044
1045
1046static void
1047convert_attribute_labels_to_offsets(void)
1048{
1049 struct pattern_attribute *attribute;
1050
1051 if (patno < 0 || !pattern[patno].attributes)
1052 return;
1053
1054 for (attribute = pattern[patno].attributes;
1055 attribute->type != LAST_ATTRIBUTE;
1056 attribute++) {
1057 if (attribute->type >= FIRST_OFFSET_ATTRIBUTE) {
1058 int label = attribute->offset;
1059 int x;
1060 int y;
1061
1062 if (label_coords[label][0] == -1) {
1063 fprintf(stderr,
1064 "%s(%d) : error : Pattern attribute uses label '%c' that wasn't specified in the diagram\n",
1065 current_file, current_line_number, label);
1066 fatal_errors++;
1067 return;
1068 }
1069
1070 TRANSFORM2(label_coords[label][0] - ci - movei,
1071 label_coords[label][1] - cj - movej, &x, &y,
1072 labels_transformation);
1073 attribute->offset = OFFSET(x, y);
1074 }
1075 }
1076}
1077
1078
1079/* On reading a line starting ':', finish up and write
1080 * out the current pattern
1081 */
1082static void
1083finish_pattern(char *line)
1084{
1085 int x;
1086 int y;
1087
1088 /* end of pattern layout */
1089 char symmetry; /* the symmetry character */
1090
1091 mini = minj = 0; /* initially : can change with edge-constraints */
1092
1093 if (num_stars > 1 || (database_type != DB_CONNECTIONS && num_stars == 0)) {
1094 fprintf(stderr, "%s(%d) : error : No or too many *'s in pattern %s\n",
1095 current_file, current_line_number, pattern_names[patno]);
1096 fatal_errors = 1;
1097 }
1098
1099 if (database_type == DB_CORNER) {
1100 ci = 0;
1101 cj = 0;
1102 }
1103 else if (choose_best_anchor && !discard_pattern) {
1104
1105 /* Try to find a better anchor if
1106 * the -m option is set.
1107 */
1108 int mi, mj; /* middle */
1109 int d, min_d = 36100;
1110 int k, min_k = -1;
1111
1112 /* We seek the element of suitable value minimizing
1113 * the distance to the middle.
1114 */
1115 mi = (maxi - 1) * 50;
1116 mj = (maxj - 1) * 50 - 1;
1117 for (k = 0; k != el; k++)
1118 if (elements[k].att < 3 && (elements[k].att & anchor) != 0) {
1119 d = gg_abs(100 * elements[k].x - mi)
1120 + gg_abs(100 * elements[k].y - mj);
1121 if (d < min_d) {
1122 min_k = k;
1123 min_d = d;
1124 }
1125 }
1126 assert(min_k != -1);
1127 ci = elements[min_k].x;
1128 cj = elements[min_k].y;
1129 pattern[patno].anchored_at_X = (elements[min_k].att == ATT_X) ? 3 : 0;
1130
1131 }
1132 else if ((ci == -1 || cj == -1) && !discard_pattern) {
1133 fprintf(stderr, "%s(%d) : No origin for pattern %s\n",
1134 current_file, current_line_number, pattern_names[patno]);
1135 fatal_errors = 1;
1136 ci = 0;
1137 cj = 0;
1138 }
1139
1140 /* translate posn of * (or Q) to relative co-ords
1141 */
1142
1143 if (num_stars == 1) {
1144 movei -= ci;
1145 movej -= cj;
1146 }
1147 else if (num_stars == 0) {
1148 movei = ci;
1149 movej = cj;
1150 }
1151
1152 TRANSFORM2(movei, movej, &x, &y, transformation_hint);
1153 pattern[patno].move_offset = OFFSET(x, y);
1154
1155 find_extents();
1156
1157 compute_grids();
1158
1159 pattern[patno].patlen = el;
1160
1161 /* Now parse the line. Only the symmetry character and the class
1162 * field are mandatory. The compiler guarantees that all the fields
1163 * are already initialized to 0.
1164 */
1165
1166 {
1167 int s;
1168 char class[80];
1169 char entry[80];
1170 char *p = line;
1171 char *p2;
1172 int n;
1173
1174 class[0] = 0; /* in case sscanf doesn't get that far */
1175 s = sscanf(p, ":%c,%[^,]%n", &symmetry, class, &n);
1176 p += n;
1177
1178 if (s < 2) {
1179 fprintf(stderr, ": line must contain symmetry character and class\n");
1180 fatal_errors++;
1181 }
1182
1183 pattern[patno].attributes = NULL;
1184 while (sscanf(p, "%*[, ]%[^,]%n", entry, &n) > 0) {
1185 const char *paren;
1186 p += n;
1187
1188 paren = strchr(entry, '(');
1189 if (paren) {
1190 struct attribute_description *description = NULL;
1191
1192 if (attribute_map) {
1193 for (description = attribute_map; description->input_name;
1194 description++) {
1195 if (strncmp(entry, description->input_name, paren - entry) == 0) {
1196 if (description->type != IN_PATTERN_VALUE) {
1197 if (!pattern[patno].attributes)
1198 pattern[patno].attributes = attributes + num_attributes;
1199
1200 attributes[num_attributes].type = description->type;
1201 if (description->type >= FIRST_OFFSET_ATTRIBUTE) {
1202 /* We store the label for now, since we don't know
1203 * its offset without having seen the constraint
1204 * diagram.
1205 */
1206 if (*(paren + 1) != '*'
1207 && !strchr(VALID_CONSTRAINT_LABELS, *(paren + 1))) {
1208 fprintf(stderr, "%s(%d) : error : '%c' is not a valid label.\n",
1209 current_file, current_line_number, *(paren + 1));
1210 fatal_errors++;
1211 continue;
1212 }
1213
1214 attributes[num_attributes].offset = *(paren + 1);
1215 }
1216 else
1217 sscanf(paren + 1, "%f", &attributes[num_attributes].value);
1218
1219 num_attributes++;
1220 }
1221 else
1222 sscanf(paren + 1, "%f", &pattern[patno].value);
1223
1224 if (!strchr(paren + 1, ')')) {
1225 fprintf(stderr, "%s(%d) : error : ')' missed\n",
1226 current_file, current_line_number);
1227 fatal_errors++;
1228 }
1229
1230 break;
1231 }
1232 }
1233 }
1234
1235 if (attribute_map == NULL || description->input_name == NULL) {
1236 fprintf(stderr, "%s(%d) : error : Unknown value field: %s\n",
1237 current_file, current_line_number, entry);
1238 fatal_errors++;
1239 break;
1240 }
1241 }
1242 else {
1243 strncpy(helper_fn_names[patno], entry, 79);
1244 break;
1245 }
1246 }
1247
1248 if (pattern[patno].attributes != NULL) {
1249 attributes[num_attributes].type = LAST_ATTRIBUTE;
1250 attributes[num_attributes].value = 0.0;
1251 num_attributes++;
1252 }
1253
1254 for (p2 = class; *p2; p2++) {
1255 switch (*p2) {
1256 case 's': pattern[patno].class |= CLASS_s; break;
1257 case 'O': pattern[patno].class |= CLASS_O; break;
1258 case 'o': pattern[patno].class |= CLASS_o; break;
1259 case 'X': pattern[patno].class |= CLASS_X; break;
1260 case 'x': pattern[patno].class |= CLASS_x; break;
1261 case 'D': pattern[patno].class |= CLASS_D; break;
1262 case 'C': pattern[patno].class |= CLASS_C; break;
1263 case 'c': pattern[patno].class |= CLASS_c; break;
1264 case 'n': pattern[patno].class |= CLASS_n; break;
1265 case 'B': pattern[patno].class |= CLASS_B; break;
1266 case 'A': pattern[patno].class |= CLASS_A; break;
1267 case 'b': pattern[patno].class |= CLASS_b; break;
1268 case 'e': pattern[patno].class |= CLASS_e; break;
1269 case 'E': pattern[patno].class |= CLASS_E; break;
1270 case 'a': pattern[patno].class |= CLASS_a; break;
1271 case 'd': pattern[patno].class |= CLASS_d; break;
1272 case 'I': pattern[patno].class |= CLASS_I; break;
1273 case 'J': pattern[patno].class |= CLASS_J; break;
1274 case 'j': pattern[patno].class |= CLASS_j; break;
1275 case 't': pattern[patno].class |= CLASS_t; break;
1276 case 'T': pattern[patno].class |= CLASS_T; break;
1277 case 'U': pattern[patno].class |= CLASS_U; break;
1278 case 'W': pattern[patno].class |= CLASS_W; break;
1279 case 'F': pattern[patno].class |= CLASS_F; break;
1280 case 'N': pattern[patno].class |= CLASS_N; break;
1281 case 'Y': pattern[patno].class |= CLASS_Y; break;
1282 case '-': break;
1283 default:
1284 if (!isgraph((int) *p2))
1285 break;
1286 fprintf(stderr,
1287 "%s(%d) : error : Unknown classification letter %c. (pattern %s).\n",
1288 current_file, current_line_number, *p2,
1289 pattern_names[patno]);
1290 fatal_errors++;
1291 break;
1292 }
1293 }
1294 }
1295
1296
1297 /* Now get the symmetry. There are extra checks we can make to do with
1298 * square-ness and edges. We do this before we work out the edge constraints,
1299 * since that mangles the size info.
1300 */
1301
1302 switch (symmetry) {
1303 case '+' :
1304 if (where & (NORTH_EDGE | EAST_EDGE | SOUTH_EDGE | WEST_EDGE))
1305 fprintf(stderr,
1306 "%s(%d) : Warning : symmetry inconsistent with edge constraints (pattern %s)\n",
1307 current_file, current_line_number, pattern_names[patno]);
1308 pattern[patno].trfno = 2;
1309 break;
1310
1311 case 'X' :
1312 if (where & (NORTH_EDGE | EAST_EDGE | SOUTH_EDGE | WEST_EDGE))
1313 fprintf(stderr,
1314 "%s(%d) : Warning : X symmetry inconsistent with edge constraints (pattern %s)\n",
1315 current_file, current_line_number, pattern_names[patno]);
1316 if (maxi != maxj)
1317 fprintf(stderr,
1318 "%s(%d) : Warning : X symmetry requires a square pattern (pattern %s)\n",
1319 current_file, current_line_number, pattern_names[patno]);
1320 pattern[patno].trfno = 2;
1321 break;
1322
1323 case '-' :
1324 if (where & (NORTH_EDGE | SOUTH_EDGE))
1325 fprintf(stderr,
1326 "%s(%d) : Warning : symmetry inconsistent with edge constraints (pattern %s)\n",
1327 current_file, current_line_number, pattern_names[patno]);
1328 pattern[patno].trfno = 4;
1329 break;
1330
1331 case '|' :
1332 if (where & (EAST_EDGE | WEST_EDGE))
1333 fprintf(stderr,
1334 "%s(%d) : Warning : symmetry inconsistent with edge constraints (pattern %s)\n",
1335 current_file, current_line_number, pattern_names[patno]);
1336 pattern[patno].trfno = 4;
1337 break;
1338
1339 case '\\' :
1340 case '/' :
1341 /* FIXME: Can't be bothered putting in the edge tests.
1342 * (What does this mean?)
1343 */
1344 if (maxi != maxj)
1345 fprintf(stderr,
1346 "%s(%d) : Warning : \\ or / symmetry requires a square pattern (pattern %s)\n",
1347 current_file, current_line_number, pattern_names[patno]);
1348
1349 pattern[patno].trfno = 4;
1350 break;
1351
1352 case 'O' :
1353 if (where & (NORTH_EDGE | EAST_EDGE | SOUTH_EDGE | WEST_EDGE))
1354 fprintf(stderr,
1355 "%s(%d) : Warning : symmetry inconsistent with edge constraints (pattern %s)\n",
1356 current_file, current_line_number, pattern_names[patno]);
1357 pattern[patno].trfno = 5; /* Ugly special convention. */
1358 break;
1359
1360 default:
1361 fprintf(stderr,
1362 "%s(%d) : Warning : symmetry character '%c' not implemented - using '8' (pattern %s)\n",
1363 current_file, current_line_number, symmetry, pattern_names[patno]);
1364 /* FALLTHROUGH */
1365 case '8' :
1366 pattern[patno].trfno = 8;
1367 break;
1368 }
1369}
1370
1371
1372static void
1373read_constraint_line(char *line)
1374{
1375 /* Avoid buffer overrun. */
1376 assert(strlen(constraint) + strlen(line) < MAXCONSTRAINT);
1377
1378 /* Append the new line. */
1379 strcat(constraint, line);
1380
1381 pattern[patno].autohelper_flag |= HAVE_CONSTRAINT;
1382}
1383
1384
1385static void
1386read_action_line(char *line)
1387{
1388 /* Avoid buffer overrun. */
1389 assert(strlen(action) + strlen(line) < MAXACTION);
1390
1391 /* Append the new line. */
1392 strcat(action, line);
1393
1394 pattern[patno].autohelper_flag |= HAVE_ACTION;
1395}
1396
1397
1398static void
1399generate_autohelper_code(int funcno, int number_of_params, int *labels)
1400{
1401 int i;
1402 char varnames[MAXPARAMS][8];
1403 char pattern_id[MAXLINE];
1404
1405 for (i = 0; i < number_of_params; i++) {
1406 if (labels[i] == (int) '*')
1407 sprintf(varnames[i], "move");
1408 /* The special label '?' represents a tenuki. We replace this
1409 * with NO_MOVE value.
1410 */
1411 else if (labels[i] == (int) '?')
1412 sprintf(varnames[i], "NO_MOVE");
1413 else
1414 sprintf(varnames[i], "%c", labels[i]);
1415 }
1416
1417 switch (autohelper_functions[funcno].type) {
1418 case 0:
1419 /* A common case. Just use the labels as parameters. */
1420 switch (number_of_params) {
1421 case 0:
1422 code_pos += sprintf(code_pos, autohelper_functions[funcno].code);
1423 break;
1424 case 1:
1425 code_pos += sprintf(code_pos, autohelper_functions[funcno].code,
1426 varnames[0]);
1427 break;
1428 case 2:
1429 code_pos += sprintf(code_pos, autohelper_functions[funcno].code,
1430 varnames[0], varnames[1]);
1431 break;
1432 case 3:
1433 code_pos += sprintf(code_pos, autohelper_functions[funcno].code,
1434 varnames[0], varnames[1], varnames[2]);
1435 break;
1436 case 4:
1437 code_pos += sprintf(code_pos, autohelper_functions[funcno].code,
1438 varnames[0], varnames[1], varnames[2],
1439 varnames[3]);
1440 break;
1441 default:
1442 fprintf(stderr, "%s(%d) : error : unknown number of parameters (pattern %s)",
1443 current_file, current_line_number, pattern_names[patno]);
1444 fatal_errors++;
1445 }
1446 break;
1447
1448 case 1:
1449 /* This is a very special case where there is assumed to be a
1450 * variable number of parameters and these constitute a series of
1451 * moves to make followed by a final attack or defense test.
1452 */
1453 if (number_of_params < autohelper_functions[funcno].params) {
1454 fprintf(stderr, "%s(%d) : error : too few parameters (pattern %s)",
1455 current_file, current_line_number, pattern_names[patno]);
1456 fatal_errors++;
1457 return;
1458 }
1459
1460 code_pos += sprintf(code_pos, autohelper_functions[funcno].code,
1461 number_of_params - autohelper_functions[funcno].params);
1462
1463 for (i = 0; i < number_of_params; i++)
1464 code_pos += sprintf(code_pos, ", %s", varnames[i]);
1465
1466 *code_pos++ = ')'; /* Close parenthesis. */
1467 break;
1468
1469 default: /* 2 */
1470 /* A very special case. We add the address of the current pattern
1471 * before the actual parameters. So far, used only by `value'.
1472 */
1473 sprintf(pattern_id, "(%s + %d)", prefix, patno);
1474
1475 switch (number_of_params) {
1476 case 0:
1477 code_pos += sprintf(code_pos, autohelper_functions[funcno].code,
1478 pattern_id);
1479 break;
1480 case 1:
1481 code_pos += sprintf(code_pos, autohelper_functions[funcno].code,
1482 pattern_id, varnames[0]);
1483 break;
1484 case 2:
1485 code_pos += sprintf(code_pos, autohelper_functions[funcno].code,
1486 pattern_id, varnames[0], varnames[1]);
1487 break;
1488 case 3:
1489 code_pos += sprintf(code_pos, autohelper_functions[funcno].code,
1490 pattern_id, varnames[0], varnames[1], varnames[2]);
1491 break;
1492 default:
1493 fprintf(stderr, "%s(%d) : error : unknown number of parameters (pattern %s)",
1494 current_file, current_line_number, pattern_names[patno]);
1495 fatal_errors++;
1496 }
1497 }
1498}
1499
1500
1501/* Parse the constraint and generate the corresponding helper code.
1502 * We use a small state machine.
1503 */
1504static void
1505parse_constraint_or_action(char *line, float *cost)
1506{
1507 int state = 0;
1508 char *p;
1509 int n = 0;
1510 int label = 0;
1511 int labels[MAXLABELS];
1512 int N = sizeof(autohelper_functions)/sizeof(struct autohelper_func);
1513 int number_of_params = 0;
1514 float cost_factor = 1.0;
1515
1516 *cost = 0.0;
1517 for (p = line; *p; p++)
1518 {
1519 switch (state) {
1520 case 0: /* Looking for a token, echoing other characters. */
1521 for (n = 0; n < N; n++) {
1522 if (strncmp(p, autohelper_functions[n].name,
1523 strlen(autohelper_functions[n].name)) == 0) {
1524 state = 1;
1525 p += strlen(autohelper_functions[n].name)-1;
1526 *cost += autohelper_functions[n].cost * cost_factor;
1527 cost_factor *= 0.6;
1528 break;
1529 }
1530 }
1531 if (state == 0 && *p != '\n')
1532 *(code_pos++) = *p;
1533 break;
1534
1535 case 1: /* Token found, now expect a '('. */
1536 if (*p != '(') {
1537 if (autohelper_functions[n].params == 0) {
1538 /* We allow to omit parenthesis when using functions which
1539 * have no parameters. In any case, you may still place them,
1540 * but having to write `value() = 50' is disgusting.
1541 */
1542 generate_autohelper_code(n, 0, NULL);
1543 p--;
1544 state = 0;
1545 break;
1546 }
1547 fprintf(stderr,
1548 "%s(%d) : error : Syntax error in constraint or action, '(' expected (pattern %s, autohelper %s).\n",
1549 current_file, current_line_number, pattern_names[patno],
1550 autohelper_functions[n].name);
1551 fatal_errors++;
1552 return;
1553 }
1554 else {
1555 assert(autohelper_functions[n].params <= MAXPARAMS);
1556 number_of_params = 0;
1557 if (autohelper_functions[n].params != 0
1558 || autohelper_functions[n].type == 1)
1559 state = 2;
1560 else
1561 state = 3;
1562 }
1563 break;
1564
1565 case 2: /* Time for a label. */
1566 if ((*p != '*') && (*p != '?') && !strchr(VALID_CONSTRAINT_LABELS, *p)) {
1567 if (strchr("XxOo", *p))
1568 fprintf(stderr,
1569 "%s(%d) : error : '%c' is not allowed as a constraint label.\n",
1570 current_file, current_line_number, *p);
1571 else
1572 fprintf(stderr,
1573 "%s(%d) : error : Syntax error in constraint or action, label expected, found '%c'.\n",
1574 current_file, current_line_number, *p);
1575 fatal_errors++;
1576 return;
1577 }
1578 else {
1579 if ((*p == '?') && (number_of_params == 0)) {
1580 fprintf(stderr,
1581 "mkpat: tenuki (?) cannot be the first label (pattern %s)\n", pattern_names[patno]);
1582 return;
1583 }
1584
1585 label = (int) *p;
1586 /* The special label '?' represents a tenuki. */
1587 if (*p != '*' && *p != '?' && label_coords[label][0] == -1) {
1588 fprintf(stderr,
1589 "%s(%d) : error : The constraint or action uses a label (%c) that wasn't specified in the diagram (pattern %s).\n",
1590 current_file, current_line_number, label, pattern_names[patno]);
1591 fatal_errors++;
1592 return;
1593 }
1594 labels[number_of_params] = label;
1595 number_of_params++;
1596 state = 3;
1597 }
1598 break;
1599
1600 case 3: /* A ',' or a ')'. */
1601 if (*p == ',') {
1602 if (autohelper_functions[n].type != 1
1603 && number_of_params == autohelper_functions[n].params) {
1604 fprintf(stderr,
1605 "%s(%d) : error : Syntax error in constraint or action, ')' expected (pattern %s).\n",
1606 current_file, current_line_number, pattern_names[patno]);
1607 return;
1608 }
1609 if (number_of_params == MAXPARAMS) {
1610 fprintf(stderr,
1611 "Error in constraint or action, too many parameters. (pattern %s).\n",
1612 pattern_names[patno]);
1613 return;
1614 }
1615 state = 2;
1616 break;
1617 }
1618 else if (*p != ')') {
1619 fprintf(stderr,
1620 "%s(%d) : error : Syntax error in constraint or action, ',' or ')' expected (pattern %s).\n",
1621 current_file, current_line_number, pattern_names[patno]);
1622 return;
1623 }
1624 else { /* a closing parenthesis */
1625 if ((autohelper_functions[n].type != 1)
1626 && (number_of_params < autohelper_functions[n].params)) {
1627 fprintf(stderr,
1628 "%s(%d) : error : Syntax error in constraint or action, %s() requires %d parameters.\n",
1629 current_file, current_line_number, autohelper_functions[n].name, autohelper_functions[n].params);
1630 fatal_errors++;
1631 return;
1632 }
1633 generate_autohelper_code(n, number_of_params, labels);
1634 state = 0;
1635 }
1636 break;
1637
1638 default:
1639 fprintf(stderr,
1640 "%s(%d) : error : Internal error in parse_constraint_or_action(), unknown state.\n",
1641 current_file, current_line_number);
1642 fatal_errors++;
1643 return;
1644
1645 }
1646 }
1647}
1648
1649/* Finish up a constraint and/or action and generate the automatic
1650 * helper code. The constraint text is in the global variable
1651 * constraint. */
1652
1653static void
1654finish_constraint_and_action(void)
1655{
1656 unsigned int i;
1657 float cost;
1658 int have_constraint = (pattern[patno].autohelper_flag & HAVE_CONSTRAINT);
1659 int have_action = (pattern[patno].autohelper_flag & HAVE_ACTION);
1660 int no_labels = 1;
1661
1662 /* Mark that this pattern has an autohelper. */
1663 pattern[patno].autohelper = dummyhelper;
1664
1665 /* Generate autohelper function declaration. */
1666 code_pos += sprintf(code_pos,
1667 "static int\nautohelper%s%d(int trans, int move, int color, int action)\n{\n int",
1668 prefix, patno);
1669
1670 /* Generate variable declarations. */
1671 for (i = 0; i < sizeof(VALID_CONSTRAINT_LABELS); i++) {
1672 int c = (int) VALID_CONSTRAINT_LABELS[i];
1673
1674 if (label_coords[c][0] != -1)
1675 code_pos += sprintf(code_pos, " %c,", c);
1676 }
1677
1678 /* Replace the last ',' with ';' */
1679 if (*(code_pos-1) == ',')
1680 *(code_pos-1) = ';';
1681 else {
1682 code_pos -= 3; /* no variable, erase "int" */
1683 code_pos += sprintf(code_pos, "UNUSED(trans);");
1684 }
1685
1686 /* Include UNUSED statements for two parameters */
1687 code_pos += sprintf(code_pos, "\n UNUSED(color);\n");
1688 if (!have_constraint || !have_action)
1689 code_pos += sprintf(code_pos, " UNUSED(action);\n");
1690
1691 /* Generate coordinate transformations. */
1692 for (i = 0; i < sizeof(VALID_CONSTRAINT_LABELS); i++) {
1693 int c = (int) VALID_CONSTRAINT_LABELS[i];
1694
1695 if (label_coords[c][0] != -1) {
1696 int x;
1697 int y;
1698
1699 TRANSFORM2(label_coords[c][0] - ci - movei,
1700 label_coords[c][1] - cj - movej, &x, &y,
1701 labels_transformation);
1702 code_pos += sprintf(code_pos,
1703 "\n %c = AFFINE_TRANSFORM(%d, trans, move);",
1704 c, OFFSET(x, y));
1705 no_labels = 0;
1706 }
1707 }
1708
1709 /* move might be unused. Add an UNUSED statement to avoid warnings. */
1710 if (no_labels)
1711 code_pos += sprintf(code_pos, "\n UNUSED(move);");
1712
1713 code_pos += sprintf(code_pos, "\n\n");
1714 if (have_constraint && have_action)
1715 code_pos += sprintf(code_pos, " if (!action)\n ");
1716 if (have_constraint) {
1717 code_pos += sprintf(code_pos, " return ");
1718 parse_constraint_or_action(constraint, &cost);
1719 pattern[patno].constraint_cost = cost;
1720 code_pos += sprintf(code_pos, ";\n");
1721 }
1722 if (have_action) {
1723 code_pos += sprintf(code_pos, " ");
1724 parse_constraint_or_action(action, &cost);
1725 code_pos += sprintf(code_pos, ";\n");
1726 code_pos += sprintf(code_pos, "\n return 0;\n");
1727 }
1728 code_pos += sprintf(code_pos, "}\n\n");
1729
1730 /* Check that we have not overrun our buffer. That would be really bad. */
1731 assert(code_pos <= autohelper_code + sizeof(autohelper_code));
1732}
1733
1734
1735
1736/* ================================================================ */
1737/* stuff to write the elements of a pattern */
1738/* ================================================================ */
1739
1740/* callback function used to sort the elements in a pattern.
1741 * We want to sort the patterns by attribute.
1742 *
1743 * RANK 01234567
1744 * ATT 57126340
1745 * ,!XOaxo.
1746 *
1747 * so that cheaper / more specific tests are done early on
1748 * For connections mode, the inhibition points (7)
1749 * must be first.
1750 */
1751
1752static int
1753compare_elements(const void *a, const void *b)
1754{
1755 /* score for each attribute */
1756 static int order[] = {7, 2, 3, 5, 6, 0, 4, 1};
1757
1758 return order[((const struct patval_b *)a)->att]
1759 - order[((const struct patval_b *)b)->att];
1760}
1761
1762struct element_node {
1763 struct patval_b e;
1764 struct element_node *next;
1765};
1766
1767/* flush out the pattern stored in elements[]. Don't forget
1768 * that elements[].{x,y} and min/max{i,j} are still relative
1769 * to the top-left corner of the original ascii pattern, and
1770 * not relative to the anchor stone ci,cj
1771 */
1772
1773static void
1774write_elements(FILE *outfile)
1775{
1776 int node;
1777 int used_nodes = 0;
1778
1779 assert(ci != -1 && cj != -1);
1780 assert(database_type == DB_DFA || transformation_hint == 0);
1781
1782 /* sort the elements so that least-likely elements are tested first. */
1783 gg_sort(elements, el, sizeof(struct patval_b), compare_elements);
1784
1785 fprintf(outfile, "static struct patval %s%d[] = {", prefix, patno);
1786
1787 for (node = 0; node < el; node++) {
1788 int x = elements[node].x;
1789 int y = elements[node].y;
1790 int att = elements[node].att;
1791 int dx;
1792 int dy;
1793
1794 assert(x >= mini && y >= minj);
1795 if (!(x <= maxi && y <= maxj)) {
1796 fprintf(stderr,
1797 "%s(%d) : error : Maximum number of elements exceeded in %s.\n",
1798 current_file, current_line_number, prefix);
1799 fatal_errors++;
1800 }
1801
1802 /* Check if this element is not needed for goal checking and by
1803 * callback function. Also, check that pattern class doesn't
1804 * require dragon status checking on it.
1805 */
1806 if ((fixed_anchor || nongoal[att]) && callback_unneeded[att]
1807 && (((pattern[patno].class & (CLASS_X | CLASS_x)) == 0)
1808 || (att != ATT_X && att != ATT_x))
1809 && (((pattern[patno].class & (CLASS_O | CLASS_o)) == 0)
1810 || (att != ATT_O && att != ATT_o))) {
1811 /* Now check that pattern matcher won't need the element for
1812 * matching itself.
1813 */
1814
1815#if GRID_OPT == 1
1816 /* If we do grid optimization, we can avoid matching 9 pattern elements
1817 * around its anchor (the 9 elements are the intersection of 16 grid
1818 * elements for all possible transformations).
1819 */
1820 if ((database_type == DB_GENERAL || database_type == DB_CONNECTIONS)
1821 && ci-1 <= x && x <= ci+1 && cj-1 <= y && y <= cj+1)
1822 continue;
1823#endif /* GRID_OPT == 1 */
1824
1825 /* DFA pattern matcher doesn't itself need these elements at all. But
1826 * they might be needed for goal checking or by callback function, so
1827 * we check it before discarding an element.
1828 */
1829 if (database_type == DB_DFA)
1830 continue;
1831 } /* If the element is discardable. */
1832
1833 if (used_nodes)
1834 fprintf(outfile, ",");
1835 fprintf(outfile, used_nodes % 4 ? "\t" : "\n ");
1836 used_nodes++;
1837
1838 TRANSFORM2(x - ci, y - cj, &dx, &dy, transformation_hint);
1839 fprintf(outfile, "{%d,%d}", OFFSET(dx, dy), att);
1840 }
1841
1842 /* This may happen if we have discarded all
1843 * the elements as unneeded by the matcher.
1844 */
1845 if (!used_nodes)
1846 fprintf(outfile, "{0,-1}}; /* Dummy element, not used. */\n\n");
1847 else
1848 fprintf(outfile, "\n};\n\n");
1849
1850 pattern[patno].patlen = used_nodes;
1851}
1852
1853
1854/* ================================================================ */
1855/* Corner database creation stuff */
1856/* ================================================================ */
1857
1858#define CORNER_DB_SIZE(patterns, variations)\
1859 ((int) ((patterns * sizeof(struct corner_pattern)\
1860 + variations * sizeof(struct corner_variation)) / 1024))
1861
1862static struct corner_variation_b corner_root;
1863static int second_corner_offset[MAXPATNO];
1864
1865static int total_variations = 0;
1866static int variations_written = 0;
1867
1868static int corner_max_width = 0;
1869static int corner_max_height = 0;
1870
1871/* This structure is used by corner_add_pattern() */
1872struct corner_element {
1873 int x;
1874 int y;
1875 int color;
1876};
1877
1878
1879/* Initialize corner variation tree. */
1880static void
1881corner_init(void)
1882{
1883 corner_root.num_variations = 0;
1884 corner_root.child = NULL;
1885}
1886
1887
1888/* corner_best_element() chooses the best element from supplied. The best
1889 * element is always selected from those which don't have other elements
1890 * closer to the corner
1891 *
1892 * +------ E.g. elements A and B are candidates to become the best
1893 * |...... element, while C and D are not (A is closer to the corner
1894 * |..A... than both C and D). Note that A and B are at "incomparable"
1895 * |..C.D. distances from the corner, since their coordinates are in
1896 * |.B.... opposite relations.
1897 * |......
1898 *
1899 * If there are existing variations among candidates, all other candidates
1900 * are automatically rejected. Once we have a set of candidates, we select
1901 * the best candidate as the one which has the best parameters (in order
1902 * of decreasing importance):
1903 * 1) maximal "corner area" (see function code);
1904 * 2) minimal distance to the corner bisector;
1905 * 3) those which x coordinate is smaller than y one
1906 *
1907 * The purpose of this function is to reduce size of variation tree (by
1908 * selecting similar variations) and allow rejecting variations as
1909 * quickly as possible (based on num_stones field value). The latter
1910 * can still be improved if a need arises.
1911 */
1912static int
1913corner_best_element(struct corner_element *el, int n,
1914 struct corner_variation_b *variations, int color)
1915{
1916 int k;
1917 int i;
1918 int best = 0;
1919 int best_value = 0;
1920
1921 int candidate[MAX_BOARD * MAX_BOARD];
1922 int candidates = 0;
1923 int existing_variation[MAX_BOARD * MAX_BOARD];
1924 int have_existing_variation = 0;
1925
1926 /* Find candidates and mark those which correspond to existing variations. */
1927 for (k = 0; k < n; k++) {
1928 for (i = 0; i < n; i++) {
1929 if (i == k)
1930 continue;
1931
1932 if (el[k].x >= el[i].x && el[k].y >= el[i].y)
1933 break;
1934 }
1935
1936 if (i == n) {
1937 struct corner_variation_b *v;
1938 int move_offset = OFFSET(el[k].x, el[k].y);
1939 int xor_att = (el[k].color == color ? ATT_O ^ ATT_O : ATT_O ^ ATT_X);
1940
1941 candidate[candidates] = k;
1942 existing_variation[candidates] = 0;
1943
1944 for (v = variations; v != NULL; v = v->next) {
1945 if (v->move_offset == move_offset
1946 && (v->xor_att == xor_att || color == 0)) {
1947 existing_variation[candidates] = 1;
1948 have_existing_variation = 1;
1949 break;
1950 }
1951 }
1952
1953 candidates++;
1954 }
1955 }
1956
1957 /* Select the best move. */
1958 for (k = 0; k < candidates; k++) {
1959 int m = candidate[k];
1960 int value = 2 * MAX_BOARD * (el[m].x + 1) * (el[m].y + 1)
1961 - 2 * gg_abs(el[m].x - el[m].y) + (el[m].x < el[m].y ? 1 : 0);
1962
1963 if (existing_variation[k] == have_existing_variation
1964 && value > best_value) {
1965 best = k;
1966 best_value = value;
1967 }
1968 }
1969
1970 return candidate[best];
1971}
1972
1973
1974/* Dynamically allocates a new variation structure. */
1975static struct corner_variation_b *
1976corner_variation_new(int move_offset, signed char xor_att,
1977 unsigned char num_stones)
1978{
1979 struct corner_variation_b *variation;
1980
1981 variation = malloc(sizeof(*variation));
1982
1983 variation->move_offset = move_offset;
1984 variation->xor_att = xor_att;
1985 variation->num_stones = num_stones;
1986 variation->num_variations = 0;
1987 variation->next = NULL;
1988 variation->child = NULL;
1989 variation->child_num = -1;
1990 variation->pattern_num = -1;
1991
1992 total_variations++;
1993
1994 return variation;
1995}
1996
1997
1998/* Follow a variation. If such a variation already exists, returns
1999 * a pointer to it. Otherwise, creates and initializes a new one.
2000 */
2001static struct corner_variation_b *
2002corner_follow_variation(struct corner_variation_b *variation,
2003 int offset, int color, unsigned char num_stones)
2004{
2005 signed char xor_att = color ? ATT_O ^ ATT_O : ATT_O ^ ATT_X;
2006 struct corner_variation_b *subvariation = variation->child;
2007 struct corner_variation_b **link = &(variation->child);
2008
2009 while (subvariation) {
2010 if (subvariation->move_offset == offset
2011 && subvariation->xor_att == xor_att) {
2012 assert(subvariation->num_stones == num_stones);
2013 return subvariation;
2014 }
2015
2016 link = &(subvariation->next);
2017 subvariation = subvariation->next;
2018 }
2019
2020 variation->num_variations++;
2021 *link = corner_variation_new(offset, xor_att, num_stones);
2022
2023 return *link;
2024}
2025
2026
2027/* Adds a pattern to corner database. */
2028static void
2029corner_add_pattern(void)
2030{
2031 int k;
2032 struct corner_element stone[MAX_BOARD * MAX_BOARD];
2033 int stones = 0;
2034 int trans;
2035 int corner_x = 0;
2036 int corner_y = 0;
2037 int color = 0;
2038 int move_pos;
2039 int move_x;
2040 int move_y;
2041 unsigned char num_stones;
2042 struct corner_variation_b *variation = &corner_root;
2043
2044 /* Check if we have a corner pattern and select appropriate transformation. */
2045 switch (where) {
2046 case SOUTH_EDGE | WEST_EDGE: trans = 5; corner_x = maxi; break;
2047 case WEST_EDGE | NORTH_EDGE: trans = 0; break;
2048 case NORTH_EDGE | EAST_EDGE: trans = 7; corner_y = maxj; break;
2049 case EAST_EDGE | SOUTH_EDGE:
2050 trans = 2; corner_x = maxi; corner_y = maxj; break;
2051
2052 default:
2053 fprintf(stderr, "%s(%d) : error : Illegal edge constraint in pattern %s\n",
2054 current_file, current_line_number, pattern_names[patno]);
2055 return;
2056 }
2057
2058 move_pos = AFFINE_TRANSFORM(pattern[patno].move_offset
2059 - OFFSET_DELTA(corner_x, corner_y), trans, POS(0, 0));
2060 move_x = I(move_pos);
2061 move_y = J(move_pos);
2062
2063 /* We need to transform labels as well. */
2064 labels_transformation = trans;
2065
2066 /* Find all pattern elements. */
2067 for (k = 0; k < el; k++) {
2068 if (elements[k].att == ATT_X || elements[k].att == ATT_O) {
2069 TRANSFORM2(elements[k].x, elements[k].y,
2070 &stone[stones].x, &stone[stones].y, trans);
2071 stone[stones].x += corner_x;
2072 stone[stones].y += corner_y;
2073 stone[stones].color = elements[k].att;
2074 stones++;
2075 }
2076 else if (elements[k].att != ATT_dot) {
2077 fprintf(stderr, "%s(%d) : error : Illegal element in pattern %s\n",
2078 current_file, current_line_number, pattern_names[patno]);
2079 return;
2080 }
2081 }
2082
2083 /* Follow variations. */
2084 for (k = 0; k < stones; k++) {
2085 int i;
2086 int best;
2087 struct corner_element stone_t;
2088
2089 if (k > 0) {
2090 best = k + corner_best_element(stone + k, stones - k, variation->child,
2091 color);
2092 stone_t = stone[k];
2093 stone[k] = stone[best];
2094 stone[best] = stone_t;
2095 }
2096 else {
2097 best = corner_best_element(stone, stones, variation->child, color);
2098 stone_t = stone[0];
2099 stone[0] = stone[best];
2100 stone[best] = stone_t;
2101 color = stone[0].color;
2102
2103 if (stone[0].x > stone[0].y) {
2104 /* To reduce number of variations, swap coordinates of all elements
2105 * unless there is one with mirrored coordinates already.
2106 */
2107 int t;
2108
2109 for (i = 1; i < k; i++) {
2110 if (stone[i].x == stone[0].y && stone[i].y == stone[0].x)
2111 break;
2112 }
2113
2114 if (i == k) {
2115 t = maxi;
2116 maxi = maxj;
2117 maxj = t;
2118
2119 t = move_x;
2120 move_x = move_y;
2121 move_y = t;
2122
2123 for (i = 0; i < stones; i++) {
2124 t = stone[i].x;
2125 stone[i].x = stone[i].y;
2126 stone[i].y = t;
2127 }
2128 }
2129 }
2130 }
2131
2132 num_stones = 1;
2133 for (i = 0; i < k; i++) {
2134 if (stone[i].x <= stone[k].x && stone[i].y <= stone[k].y)
2135 num_stones++;
2136 }
2137
2138 variation = corner_follow_variation(variation,
2139 OFFSET(stone[k].x, stone[k].y), stone[k].color == color,
2140 num_stones);
2141 }
2142
2143 /* Finally, follow the pattern move as a variation. */
2144 num_stones = 1;
2145 for (k = 0; k < stones; k++) {
2146 if (stone[k].x <= move_x && stone[k].y <= move_y)
2147 num_stones++;
2148 }
2149
2150 variation = corner_follow_variation(variation, OFFSET(move_x, move_y),
2151 ATT_O == color, num_stones);
2152 if (variation->pattern_num == -1) {
2153 variation->pattern_num = patno;
2154 second_corner_offset[patno] = OFFSET(maxi, maxj);
2155 if (maxi > corner_max_height)
2156 corner_max_height = maxi;
2157 if (maxj > corner_max_width)
2158 corner_max_width = maxj;
2159 }
2160 else {
2161 fprintf(stderr, "%s(%d) : warning : duplicated patterns encountered (%s and %s)\n",
2162 current_file, current_line_number,
2163 pattern_names[variation->pattern_num], pattern_names[patno]);
2164 discard_pattern = 1;
2165 }
2166}
2167
2168
2169/* Enumerates all variations so that we know addresses of subvariations
2170 * when it is time to write them into a .c file.
2171 */
2172static int
2173corner_pack_variations(struct corner_variation_b *variation, int counter)
2174{
2175 counter++;
2176 if (variation->next)
2177 counter = corner_pack_variations(variation->next, counter);
2178 if (variation->child) {
2179 variation->child_num = counter;
2180 counter = corner_pack_variations(variation->child, counter);
2181 }
2182
2183 return counter;
2184}
2185
2186
2187/* Write variations recursively into an array. */
2188static void
2189corner_write_variations(struct corner_variation_b *variation, FILE *outfile)
2190{
2191 fprintf(outfile, " {%d,%d,%d,%d,", variation->move_offset,
2192 variation->xor_att, variation->num_stones,
2193 variation->num_variations);
2194 if (variation->child)
2195 fprintf(outfile, "&%s_variations[%d],", prefix, variation->child_num);
2196 else
2197 fprintf(outfile, "NULL,");
2198 if (variation->pattern_num != -1)
2199 fprintf(outfile, "&%s[%d]", prefix, variation->pattern_num);
2200 else
2201 fprintf(outfile, "NULL");
2202
2203 variations_written++;
2204 if (variations_written != total_variations)
2205 fprintf(outfile, "},\n");
2206 else
2207 fprintf(outfile, "}\n};\n\n\n");
2208
2209 if (variation->next)
2210 corner_write_variations(variation->next, outfile);
2211 if (variation->child)
2212 corner_write_variations(variation->child, outfile);
2213}
2214
2215
2216
2217static void
2218write_attributes(FILE *outfile)
2219{
2220 int k;
2221
2222 fprintf(outfile, "static struct pattern_attribute attributes[] = {\n");
2223 fprintf(outfile, "#ifdef HAVE_TRANSPARENT_UNIONS\n");
2224
2225 for (k = 0; k < num_attributes; k++) {
2226 fprintf(outfile, " {%s,", attribute_name[attributes[k].type]);
2227 if (attributes[k].type >= FIRST_OFFSET_ATTRIBUTE)
2228 fprintf(outfile, "{.offset=%d}}", attributes[k].offset);
2229 else
2230 fprintf(outfile, "{.value=%f}}", attributes[k].value);
2231
2232 if (k != num_attributes - 1)
2233 fprintf(outfile, ",\n");
2234 }
2235
2236 fprintf(outfile, "\n#else\n");
2237
2238 for (k = 0; k < num_attributes; k++) {
2239 fprintf(outfile, " {%s,", attribute_name[attributes[k].type]);
2240 if (attributes[k].type >= FIRST_OFFSET_ATTRIBUTE)
2241 fprintf(outfile, "0.0,%d}", attributes[k].offset);
2242 else
2243 fprintf(outfile, "%f,0}", attributes[k].value);
2244
2245 if (k != num_attributes - 1)
2246 fprintf(outfile, ",\n");
2247 }
2248
2249 fprintf(outfile, "\n#endif\n};\n\n");
2250}
2251
2252
2253/* Sort and write out the patterns. */
2254static void
2255write_patterns(FILE *outfile)
2256{
2257 int j;
2258
2259 /* Write out the patterns. */
2260 if (database_type == DB_CORNER)
2261 fprintf(outfile, "static struct corner_pattern %s[] = {\n", prefix);
2262 else
2263 fprintf(outfile, "static struct pattern %s[] = {\n", prefix);
2264
2265 for (j = 0; j < patno; ++j) {
2266 struct pattern *p = pattern + j;
2267
2268 if (database_type == DB_CORNER) {
2269 fprintf(outfile, " {%d,%d,0x%x,\"%s\",",
2270 second_corner_offset[j], (p->trfno == 4),
2271 p->class, pattern_names[j]);
2272
2273 if (attributes_needed) {
2274 fprintf(outfile, "attributes+%d,",
2275 (int) (p->attributes ? p->attributes - attributes : 0));
2276 }
2277 else
2278 fprintf(outfile, "NULL,");
2279
2280 fprintf(outfile, "%d,", p->autohelper_flag);
2281
2282 if (p->autohelper)
2283 fprintf(outfile, "autohelper%s%d}", prefix, j);
2284 else
2285 fprintf(outfile, "NULL}");
2286
2287 if (j != patno - 1)
2288 fprintf(outfile, ",\n");
2289 else
2290 fprintf(outfile, "\n};\n\n\n");
2291
2292 continue;
2293 }
2294
2295 /* p->min{i,j} and p->max{i,j} are the maximum extent of the elements,
2296 * including any rows of '?' which do not feature in the elements list.
2297 * ie they are the positions of the topleft and bottomright corners of
2298 * the pattern, relative to the pattern origin. These just transform same
2299 * as the elements.
2300 */
2301 fprintf(outfile, " {%s%d,%d,%d, \"%s\",%d,%d,%d,%d,%d,%d,0x%x,%d",
2302 prefix, j,
2303 p->patlen,
2304 p->trfno,
2305 pattern_names[j],
2306 p->mini, p->minj,
2307 p->maxi, p->maxj,
2308 p->maxi - p->mini, /* height */
2309 p->maxj - p->minj, /* width */
2310 p->edge_constraints,
2311 p->move_offset);
2312
2313
2314#if GRID_OPT
2315 fprintf(outfile, ",\n {");
2316 {
2317 int ll;
2318
2319 for (ll = 0; ll < 8; ++ll)
2320 fprintf(outfile, " 0x%08x%s", p->and_mask[ll], ll < 7 ? "," : "");
2321 fprintf(outfile, "},\n {");
2322 for (ll = 0; ll < 8; ++ll)
2323 fprintf(outfile, " 0x%08x%s", p->val_mask[ll], ll < 7 ? "," : "");
2324 }
2325 fprintf(outfile, "}\n ");
2326#endif
2327
2328 fprintf(outfile, ", 0x%x,%f,", p->class, p->value);
2329
2330 if (attributes_needed) {
2331 fprintf(outfile, "attributes+%d,",
2332 (int) (p->attributes ? p->attributes - attributes : 0));
2333 }
2334 else
2335 fprintf(outfile, "NULL,");
2336
2337 fprintf(outfile, "%d,%s,", p->autohelper_flag, helper_fn_names[j]);
2338
2339 if (p->autohelper)
2340 fprintf(outfile, "autohelper%s%d", prefix, j);
2341 else
2342 fprintf(outfile, "NULL");
2343 fprintf(outfile, ",%d", p->anchored_at_X);
2344 fprintf(outfile, ",%f", p->constraint_cost);
2345#if PROFILE_PATTERNS
2346 fprintf(outfile, ",0,0");
2347 fprintf(outfile, ",0");
2348#endif
2349
2350 fprintf(outfile, "},\n");
2351 }
2352
2353 if (database_type == DB_CORNER)
2354 return;
2355
2356 /* Add a final empty entry. */
2357 fprintf(outfile, " {NULL, 0,0,NULL,0,0,0,0,0,0,0,0");
2358#if GRID_OPT
2359 fprintf(outfile, ",{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}");
2360#endif
2361 fprintf(outfile, ",0,0.0,NULL,0,NULL,NULL,0,0.0");
2362#if PROFILE_PATTERNS
2363 fprintf(outfile, ",0,0,0");
2364#endif
2365 fprintf(outfile, "}\n};\n");
2366}
2367
2368/* Write out the pattern db */
2369static void
2370write_pattern_db(FILE *outfile)
2371{
2372 if (database_type == DB_CORNER) {
2373 fprintf(outfile, "struct corner_db %s_db = {\n", prefix);
2374 fprintf(outfile, " %d,\n", corner_max_width + 1);
2375 fprintf(outfile, " %d,\n", corner_max_height + 1);
2376 fprintf(outfile, " %d,\n", corner_root.num_variations);
2377 fprintf(outfile, " %s_variations\n", prefix);
2378 fprintf(outfile, "};\n");
2379
2380 return;
2381 }
2382
2383 /* Write out the pattern database. */
2384 fprintf(outfile, "\n");
2385 fprintf(outfile, "struct pattern_db %s_db = {\n", prefix);
2386 fprintf(outfile, " -1,\n"); /* fixed_for_size */
2387 fprintf(outfile, " %d,\n", fixed_anchor);
2388 fprintf(outfile, " %s\n", prefix);
2389 if (database_type == DB_DFA)
2390 fprintf(outfile, " ,& dfa_%s\n", prefix); /* pointer to the wired dfa */
2391 else
2392 fprintf(outfile, " , NULL\n"); /* pointer to a possible dfa */
2393
2394 fprintf(outfile, "};\n");
2395}
2396
2397
2398int
2399main(int argc, char *argv[])
2400{
2401 static char stdin_name[] = "<stdin>";
2402 int input_files = 0;
2403 int ifc;
2404 char *input_file_names[MAX_INPUT_FILE_NAMES];
2405 char *output_file_name = NULL;
2406 char *transformations_file_name = NULL;
2407 FILE *input_FILE = stdin;
2408 FILE *output_FILE = stdout;
2409 FILE *transformations_FILE = NULL;
2410 int state = 0;
2411 char *save_code_pos = autohelper_code;
2412 int iterations = 0;
2413
2414 transformation_init();
2415
2416 {
2417 int i;
2418 int multiple_anchor_options = 0;
2419
2420 /* Parse command-line options */
2421 while ((i = gg_getopt(argc, argv, "i:o:t:vV:pcfCDd:A:OXbma")) != EOF) {
2422 switch (i) {
2423 case 'i':
2424 if (input_files == MAX_INPUT_FILE_NAMES) {
2425 fprintf(stderr, "Error : Too many input files (maximum %d supported)\n",
2426 MAX_INPUT_FILE_NAMES);
2427 return EXIT_FAILURE;
2428 }
2429 input_file_names[input_files++] = gg_optarg;
2430 break;
2431
2432 case 'o': output_file_name = gg_optarg; break;
2433 case 't': transformations_file_name = gg_optarg; break;
2434 case 'v': verbose = 1; break;
2435 case 'V': dfa_verbose = strtol(gg_optarg, NULL, 10); break;
2436
2437 case 'p':
2438 case 'c':
2439 case 'f':
2440 case 'C':
2441 case 'D':
2442 case 'd':
2443 if (database_type) {
2444 fprintf(stderr, "Error : More than one database type specified (-%c and -%c)\n",
2445 database_type, i);
2446 return 1;
2447 }
2448 database_type = i;
2449 if (i == 'd') {
2450 iterations = strtol(gg_optarg, NULL, 10);
2451 if (iterations < 0) {
2452 fprintf(stderr, "Error : Expected a non-negative number of iterations\n");
2453 return 1;
2454 }
2455 }
2456 break;
2457
2458 case 'O':
2459 if (anchor)
2460 multiple_anchor_options = 1;
2461 anchor = ANCHOR_O;
2462 break;
2463 case 'X':
2464 if (anchor)
2465 multiple_anchor_options = 1;
2466 anchor = ANCHOR_X;
2467 break;
2468 case 'b':
2469 if (anchor)
2470 multiple_anchor_options = 1;
2471 anchor = ANCHOR_BOTH;
2472 break;
2473
2474 case 'm':
2475 choose_best_anchor = 1;
2476 if (fixed_anchor)
2477 fprintf(stderr, "Warning : -m and -a are mutually exclusive.\n");
2478 break;
2479 case 'a':
2480 fixed_anchor = 1;
2481 if (choose_best_anchor)
2482 fprintf(stderr, "Warning : -m and -a are mutually exclusive.\n");
2483 break;
2484
2485 default:
2486 fprintf(stderr, "\b ; ignored\n");
2487 }
2488 }
2489
2490 if (!database_type)
2491 database_type = DB_GENERAL;
2492 if (!anchor)
2493 anchor = ANCHOR_O;
2494
2495 if (!input_files)
2496 input_file_names[input_files++] = stdin_name;
2497 if (output_file_name && database_type != OPTIMIZE_DFA) {
2498 output_FILE = fopen(output_file_name, "wb");
2499 if (output_FILE == NULL) {
2500 fprintf(stderr, "Error : Cannot write to file %s\n", output_file_name);
2501 return 1;
2502 }
2503 }
2504 if (transformations_file_name
2505 && (database_type == DB_DFA || database_type == OPTIMIZE_DFA)) {
2506 transformations_FILE = fopen(transformations_file_name, "r");
2507 if (transformations_FILE) {
2508 parse_transformations_file(transformations_FILE);
2509 fclose(transformations_FILE);
2510 }
2511 else if (database_type == DB_DFA) {
2512 fprintf(stderr, "Error : Cannot read file %s\n",
2513 transformations_file_name);
2514 return 1;
2515 }
2516 }
2517
2518 if (multiple_anchor_options)
2519 fprintf(stderr, "Warning : Multiple anchor options encountered. The last took precedence\n");
2520 }
2521
2522 if (gg_optind >= argc) {
2523 fputs(USAGE, stderr);
2524 exit(EXIT_FAILURE);
2525 }
2526
2527 prefix = argv[gg_optind];
2528
2529 if (database_type == DB_DFA) {
2530 dfa_init();
2531 new_dfa(&dfa, "mkpat's dfa");
2532 }
2533 else if (database_type == DB_CORNER)
2534 corner_init();
2535
2536 if (database_type == OPTIMIZE_DFA) {
2537 if (transformations_file_name == NULL) {
2538 fprintf(stderr, "error : transformation file required (use -t option)\n");
2539 return 1;
2540 }
2541 dfa_patterns_reset(&dfa_pats);
2542 dfa_init();
2543 }
2544 else
2545 fprintf(output_FILE, PREAMBLE);
2546
2547 /* Initialize pattern number and buffer for automatically generated
2548 * helper code.
2549 */
2550 patno = -1;
2551 autohelper_code[0] = 0;
2552 code_pos = autohelper_code;
2553
2554 num_attributes = 1;
2555 attributes[0].type = LAST_ATTRIBUTE;
2556
2557 /* Parse the input file, output pattern elements as as we find them,
2558 * and store pattern entries for later output.
2559 *
2560 * We do this parsing too with the help of a state machine.
2561 * state
2562 * 0 Waiting for a Pattern line.
2563 * 1 Pattern line found, waiting for a position diagram.
2564 * 2 Reading position diagram.
2565 * 3 Waiting for entry line (":" line).
2566 * 4 Waiting for optional constraint diagram.
2567 * 5 Reading constraint diagram.
2568 * 6 Waiting for constraint line (";" line).
2569 * 7 Reading a constraint
2570 * 8 Reading an action
2571 *
2572 * FIXME: This state machine should be possible to simplify.
2573 *
2574 */
2575
2576 for (ifc = 0; ifc < input_files && !fatal_errors; ifc++) {
2577 char line[MAXLINE]; /* current line from file */
2578
2579 if (input_file_names[ifc] != stdin_name) {
2580 input_FILE = fopen(input_file_names[ifc], "r");
2581 if (input_FILE == NULL) {
2582 fprintf(stderr, "Error: Cannot open file %s\n", input_file_names[ifc]);
2583 return 1;
2584 }
2585 }
2586
2587 current_file = input_file_names[ifc];
2588 current_line_number = 0;
2589
2590 while (fgets(line, MAXLINE, input_FILE)) {
2591 int command = 0;
2592 char command_data[MAXLINE];
2593
2594 current_line_number++;
2595 if (line[strlen(line)-1] != '\n') {
2596 fprintf(stderr, "%s(%d) : Error : line truncated (longer than %d characters)\n",
2597 current_file, current_line_number, MAXLINE - 1);
2598
2599 fatal_errors++;
2600 }
2601
2602 /* Remove trailing white space from `line' */
2603 {
2604 int i = strlen(line) - 2; /* Start removing backwards just before newline */
2605 while (i >= 0 && isspace((int) line[i]))
2606 i--;
2607 line[i+1] = '\n';
2608 line[i+2] = '\0';
2609 }
2610
2611 if (sscanf(line, "Pattern %s", command_data) == 1)
2612 command = 1;
2613 else if (sscanf(line, "goal_elements %s", command_data) == 1)
2614 command = 2;
2615 else if (sscanf(line, "callback_data %s", command_data) == 1)
2616 command = 3;
2617 else if (sscanf(line, "attribute_map %s", command_data) == 1)
2618 command = 4;
2619
2620 if (command) {
2621 char *p = strpbrk(command_data, " \t");
2622
2623 if (p)
2624 *p = 0;
2625
2626 if (patno >= 0) {
2627 switch (state) {
2628 case 1:
2629 fprintf(stderr, "%s(%d) : Warning: empty pattern %s\n",
2630 current_file, current_line_number, pattern_names[patno]);
2631 break;
2632 case 2:
2633 case 3:
2634 fprintf(stderr, "%s(%d) : Error : No entry line for pattern %s\n",
2635 current_file, current_line_number, pattern_names[patno]);
2636 fatal_errors++;
2637 break;
2638 case 5:
2639 case 6:
2640 {
2641 struct pattern_attribute *attribute = NULL;
2642
2643 if (pattern[patno].attributes) {
2644 for (attribute = pattern[patno].attributes;
2645 attribute->type != LAST_ATTRIBUTE;
2646 attribute++) {
2647 if (attribute->type >= FIRST_OFFSET_ATTRIBUTE)
2648 break;
2649 }
2650 }
2651
2652 if (attribute == NULL || attribute->type == LAST_ATTRIBUTE) {
2653 fprintf(stderr,
2654 "%s(%d) : Warning: constraint diagram but no constraint line or offset attributes for pattern %s\n",
2655 current_file, current_line_number, pattern_names[patno]);
2656 }
2657 }
2658
2659 break;
2660 case 7:
2661 case 8:
2662 finish_constraint_and_action();
2663 /* fall through */
2664 case 0:
2665 case 4:
2666 check_constraint_diagram();
2667 }
2668 }
2669
2670 state = 0;
2671 if (command == 1) { /* Pattern `name' */
2672 int k;
2673
2674 if (!discard_pattern) {
2675 convert_attribute_labels_to_offsets();
2676 patno++;
2677 }
2678 else
2679 code_pos = save_code_pos;
2680 reset_pattern();
2681
2682 if (strlen(command_data) > MAXNAME - 1) {
2683 fprintf(stderr, "%s(%d) : Warning : pattern name is too long, truncated\n",
2684 current_file, current_line_number);
2685 command_data[MAXNAME - 1] = 0;
2686 }
2687
2688 /* Somewhat inefficient, but doesn't take any real time
2689 * given current database sizes.
2690 */
2691 for (k = 0; k < patno; k++) {
2692 if (strcmp(pattern_names[k], command_data) == 0) {
2693 fprintf(stderr, "%s(%d) : Warning : duplicate pattern name `%s'\n",
2694 current_file, current_line_number, command_data);
2695 break;
2696 }
2697 }
2698
2699 strcpy(pattern_names[patno], command_data);
2700
2701 transformation_hint = find_transformation_hint(pattern_names[patno]);
2702
2703 state = 1;
2704 discard_pattern = 0;
2705 }
2706 else if (command == 2 || command == 3) {
2707 int *sort_out = (command == 2 ? nongoal : callback_unneeded);
2708 int k;
2709
2710 for (k = 0; k < 8; k++)
2711 sort_out[k] = 1;
2712
2713 if (strcmp(command_data, "none")) {
2714 char *c;
2715
2716 for (c = command_data; *c; c++) {
2717 switch (*c) {
2718 case '.':
2719 sort_out[ATT_dot] = 0;
2720 if (command == 2) { /* goal_elements */
2721 sort_out[ATT_comma] = 0;
2722 sort_out[ATT_not] = 0;
2723 }
2724 break;
2725 case 'X': sort_out[ATT_X] = 0; break;
2726 case 'O': sort_out[ATT_O] = 0; break;
2727 case 'x': sort_out[ATT_x] = 0; break;
2728 case 'o': sort_out[ATT_o] = 0; break;
2729 case ',':
2730 sort_out[ATT_comma] = 0;
2731 if (command != 2)
2732 break;
2733 case '!':
2734 sort_out[ATT_not] = 0;
2735 if (command != 2)
2736 break;
2737 default:
2738 fprintf(stderr, "%s(%d) : Error : illegal character `%c'\n",
2739 current_file, current_line_number, *c);
2740 fatal_errors++;
2741 }
2742 }
2743 }
2744 }
2745 else {
2746 struct attribute_description *old_map = attribute_map;
2747
2748 if (strcmp(command_data, "general") == 0) {
2749 attribute_map = general_attribute_map;
2750 attributes_needed = 1;
2751 }
2752 else if (strcmp(command_data, "value_only") == 0) {
2753 attribute_map = value_only_attribute_map;
2754 attributes_needed = 0;
2755 }
2756 else if (strcmp(command_data, "owl_attack") == 0) {
2757 attribute_map = owl_attack_attribute_map;
2758 attributes_needed = 1;
2759 }
2760 else if (strcmp(command_data, "owl_defense") == 0) {
2761 attribute_map = owl_defense_attribute_map;
2762 attributes_needed = 1;
2763 }
2764 else if (strcmp(command_data, "none") == 0) {
2765 attribute_map = NULL;
2766 attributes_needed = 0;
2767 }
2768 else {
2769 fprintf(stderr, "%s(%d) : Error : unknown attribute map `%s'",
2770 current_file, current_line_number, command_data);
2771 fatal_errors++;
2772 }
2773
2774 if (patno != -1 && attribute_map != old_map) {
2775 fprintf(stderr, "%s(%d) : Error : attribute map can only be set before the first pattern\n",
2776 current_file, current_line_number);
2777 fatal_errors++;
2778 }
2779 }
2780 }
2781 else if (line[0] == '\n' || line[0] == '#') {
2782 /* nothing */
2783 if (state == 2 || state == 5) {
2784 if (state == 5)
2785 check_constraint_diagram_size();
2786 state++;
2787 }
2788 }
2789 else if (strchr(VALID_PATTERN_CHARS, line[0])
2790 || strchr(VALID_EDGE_CHARS, line[0])
2791 || strchr(VALID_CONSTRAINT_LABELS, line[0])) {
2792 /* diagram line */
2793 switch (state) {
2794 case 0:
2795 case 3:
2796 case 6:
2797 case 7:
2798 case 8:
2799 fprintf(stderr,
2800 "%s(%d) : error : What, another diagram here? (pattern %s)\n",
2801 current_file, current_line_number, pattern_names[patno]);
2802 fatal_errors++;
2803 break;
2804 case 1:
2805 state++; /* fall through */
2806 case 2:
2807 if (!read_pattern_line(line)) {
2808 discard_pattern = 1;
2809 el = 0;
2810 }
2811 break;
2812 case 4:
2813 state++; /* fall through */
2814 case 5:
2815 read_constraint_diagram_line(line);
2816 break;
2817 }
2818 }
2819 else if (line[0] == ':') {
2820 if (state == 2 || state == 3) {
2821 finish_pattern(line);
2822
2823 if (!discard_pattern) {
2824 if (database_type == DB_DFA || database_type == OPTIMIZE_DFA)
2825 write_to_dfa(patno);
2826 if (database_type == DB_CORNER)
2827 corner_add_pattern();
2828 else if (database_type != OPTIMIZE_DFA)
2829 write_elements(output_FILE);
2830 }
2831
2832 state = 4;
2833 save_code_pos = code_pos;
2834 }
2835 else {
2836 fprintf(stderr,
2837 "%s(%d) : warning : Unexpected entry line in pattern %s\n",
2838 current_file, current_line_number, pattern_names[patno]);
2839 }
2840 }
2841 else if (line[0] == ';') {
2842 if (state == 5)
2843 check_constraint_diagram_size();
2844
2845 if (state == 5 || state == 6 || state == 7) {
2846 read_constraint_line(line+1);
2847 state = 7;
2848 }
2849 else {
2850 fprintf(stderr, "%s(%d) : Warning: unexpected constraint line in pattern %s\n",
2851 current_file, current_line_number, pattern_names[patno]);
2852 }
2853 }
2854 else if (line[0] == '>') {
2855 if (state == 4 || state == 5 || state == 6
2856 || state == 7 || state == 8) {
2857 if (state == 5)
2858 check_constraint_diagram_size();
2859 read_action_line(line+1);
2860 state = 8;
2861 }
2862 else {
2863 fprintf(stderr, "Warning: unexpected action line in pattern %s\n",
2864 pattern_names[patno]);
2865 }
2866 }
2867 else {
2868 int i = strlen(line);
2869 char c = line[i-1];
2870 line[i-1] = 0; /* Chop off \n */
2871 fprintf(stderr, "%s(%d) : error : Malformed line \"%s\" in pattern %s\n",
2872 current_file, current_line_number, line, pattern_names[patno]);
2873 line[i-1] = c; /* Put it back - maybe not necessary at this point. */
2874 fatal_errors++;
2875 }
2876 } /* while not EOF */
2877 } /* for each file */
2878
2879 convert_attribute_labels_to_offsets();
2880
2881 if (patno >= 0) {
2882 switch (state) {
2883 case 1:
2884 fprintf(stderr, "Warning: empty pattern %s\n",
2885 pattern_names[patno]);
2886 break;
2887 case 2:
2888 case 3:
2889 fprintf(stderr, "%s(%d) : Error : no entry line for pattern %s\n",
2890 current_file, current_line_number, pattern_names[patno]);
2891 fatal_errors++;
2892 break;
2893 case 5:
2894 case 6:
2895 fprintf(stderr,
2896 "Warning: constraint diagram but no constraint line for pattern %s\n",
2897 pattern_names[patno]);
2898 break;
2899 case 7:
2900 case 8:
2901 finish_constraint_and_action(); /* fall through */
2902 case 0:
2903 case 4:
2904 check_constraint_diagram();
2905 patno++;
2906 reset_pattern();
2907 }
2908 }
2909
2910 if (discard_pattern) {
2911 patno--;
2912 code_pos = save_code_pos;
2913 }
2914
2915 *code_pos = 0;
2916
2917 if (verbose)
2918 fprintf(stderr, "%d / %d patterns have edge-constraints\n",
2919 pats_with_constraints, patno);
2920
2921 if (database_type != OPTIMIZE_DFA) {
2922 /* Forward declaration, which autohelpers might need. */
2923 if (database_type != DB_CORNER)
2924 fprintf(output_FILE, "static struct pattern %s[%d];\n\n", prefix, patno + 1);
2925 else
2926 fprintf(output_FILE, "static struct corner_pattern %s[%d];\n\n", prefix, patno + 1);
2927
2928 /* Write the autohelper code. */
2929 fprintf(output_FILE, "%s", autohelper_code);
2930
2931 if (attributes_needed)
2932 write_attributes(output_FILE);
2933 else
2934 assert(num_attributes == 1);
2935
2936 write_patterns(output_FILE);
2937
2938 if (database_type == DB_DFA) {
2939 fprintf(stderr, "---------------------------\n");
2940
2941 dfa_finalize(&dfa);
2942 dfa_shuffle(&dfa);
2943
2944 fprintf(stderr, "DFA for %s\n", prefix);
2945 fprintf(stderr, "size: %d kB for ", dfa_size(&dfa));
2946 fprintf(stderr, "%d patterns", patno);
2947 fprintf(stderr, " (%d states)\n", dfa.last_state);
2948
2949 strcpy(dfa.name, prefix);
2950 print_c_dfa(output_FILE, prefix, &dfa);
2951 fprintf(stderr, "---------------------------\n");
2952
2953 if (DFA_MAX_MATCHED/8 < dfa_calculate_max_matched_patterns(&dfa))
2954 fprintf(stderr, "Warning: Increase DFA_MAX_MATCHED in 'dfa.h'.\n");
2955
2956 kill_dfa(&dfa);
2957 dfa_end();
2958 }
2959
2960 if (database_type == DB_CORNER) {
2961 fprintf(stderr, "---------------------------\n");
2962
2963 corner_pack_variations(corner_root.child, 0);
2964 fprintf(output_FILE, "static struct corner_variation %s_variations[] = {\n",
2965 prefix);
2966 corner_write_variations(corner_root.child, output_FILE);
2967
2968 fprintf(stderr, "corner database for %s\n", prefix);
2969 fprintf(stderr, "size: %d kB for %d patterns (%d variations)\n",
2970 CORNER_DB_SIZE(patno, total_variations), patno, total_variations);
2971 fprintf(stderr, "---------------------------\n");
2972 }
2973
2974 write_pattern_db(output_FILE);
2975
2976 if (fatal_errors) {
2977 fprintf(output_FILE, "\n#error: One or more fatal errors compiling %s\n",
2978 current_file);
2979 }
2980 }
2981 else { /* database_type == OPTIMIZE_DFA */
2982 int k;
2983 int *optimized_variations;
2984
2985 transformations_FILE = fopen(transformations_file_name, "wb");
2986 if (transformations_FILE == NULL) {
2987 fprintf(stderr, "error : cannot write to file %s\n",
2988 transformations_file_name);
2989 }
2990
2991 optimized_variations = dfa_patterns_optimize_variations(&dfa_pats,
2992 iterations);
2993 for (k = 0; k < patno; k++) {
2994 fprintf(transformations_FILE, "%s\t%d\n", pattern_names[k],
2995 optimized_variations[k]);
2996 }
2997
2998 free(optimized_variations);
2999 dfa_end();
3000 }
3001
3002 return fatal_errors ? 1 : 0;
3003}
3004
3005
3006/*
3007 * Local Variables:
3008 * tab-width: 8
3009 * c-basic-offset: 2
3010 * End:
3011 */