1 /* tables.c - tables serialization code
3 * Copyright (c) 1990 The Regents of the University of California.
6 * This code is derived from software contributed to Berkeley by
9 * The United States Government has rights in this work pursuant
10 * to contract no. DE-AC03-76SF00098 between the United States
11 * Department of Energy and the University of California.
13 * This file is part of flex.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
25 * Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
30 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
31 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39 /** Convert size_t to t_flag.
43 #define BYTES2TFLAG(n)\
44 (((n) == sizeof(flex_int8_t))\
46 :(((n)== sizeof(flex_int16_t))\
50 /** Clear YYTD_DATA* bit flags
51 * @return the flag with the YYTD_DATA* bits cleared
53 #define TFLAGS_CLRDATA(flg) ((flg) & ~(YYTD_DATA8 | YYTD_DATA16 | YYTD_DATA32))
55 int yytbl_write32 (struct yytbl_writer *wr, flex_uint32_t v);
56 int yytbl_write16 (struct yytbl_writer *wr, flex_uint16_t v);
57 int yytbl_write8 (struct yytbl_writer *wr, flex_uint8_t v);
58 int yytbl_writen (struct yytbl_writer *wr, void *v, flex_int32_t len);
59 static flex_int32_t yytbl_data_geti (const struct yytbl_data *tbl, int i);
60 static flex_int32_t yytbl_data_getijk (const struct yytbl_data *tbl, int i,
64 /** Initialize the table writer.
65 * @param wr an uninitialized writer
66 * @param the output file
67 * @return 0 on success
69 int yytbl_writer_init (struct yytbl_writer *wr, FILE * out)
72 wr->total_written = 0;
76 /** Initialize a table header.
77 * @param th The uninitialized structure
78 * @param version_str the version string
79 * @param name the name of this table set
81 int yytbl_hdr_init (struct yytbl_hdr *th, const char *version_str,
84 memset (th, 0, sizeof (struct yytbl_hdr));
86 th->th_magic = YYTBL_MAGIC;
87 th->th_hsize = 14 + strlen (version_str) + 1 + strlen (name) + 1;
88 th->th_hsize += yypad64 (th->th_hsize);
89 th->th_ssize = 0; // Not known at this point.
91 th->th_version = copy_string (version_str);
92 th->th_name = copy_string (name);
96 /** Allocate and initialize a table data structure.
97 * @param tbl a pointer to an uninitialized table
98 * @param id the table identifier
99 * @return 0 on success
101 int yytbl_data_init (struct yytbl_data *td, enum yytbl_id id)
104 memset (td, 0, sizeof (struct yytbl_data));
106 td->td_flags = YYTD_DATA32;
110 /** Clean up table and data array.
111 * @param td will be destroyed
112 * @return 0 on success
114 int yytbl_data_destroy (struct yytbl_data *td)
123 /** Write enough padding to bring the file pointer to a 64-bit boundary. */
124 static int yytbl_write_pad64 (struct yytbl_writer *wr)
126 int pad, bwritten = 0;
128 pad = yypad64 (wr->total_written);
130 if (yytbl_write8 (wr, 0) < 0)
137 /** write the header.
138 * @param out the output stream
139 * @param th table header to be written
140 * @return -1 on error, or bytes written on success.
142 int yytbl_hdr_fwrite (struct yytbl_writer *wr, const struct yytbl_hdr *th)
147 if (yytbl_write32 (wr, th->th_magic) < 0
148 || yytbl_write32 (wr, th->th_hsize) < 0)
149 flex_die (_("th_magic|th_hsize write32 failed"));
152 if (fgetpos (wr->out, &(wr->th_ssize_pos)) != 0)
153 flex_die (_("fgetpos failed"));
155 if (yytbl_write32 (wr, th->th_ssize) < 0
156 || yytbl_write16 (wr, th->th_flags) < 0)
157 flex_die (_("th_ssize|th_flags write failed"));
160 sz = strlen (th->th_version) + 1;
161 if ((rv = yytbl_writen (wr, th->th_version, sz)) != sz)
162 flex_die (_("th_version writen failed"));
165 sz = strlen (th->th_name) + 1;
166 if ((rv = yytbl_writen (wr, th->th_name, sz)) != sz)
167 flex_die (_("th_name writen failed"));
171 if ((rv = yytbl_write_pad64 (wr)) < 0)
172 flex_die (_("pad64 failed"));
176 if (bwritten != (int) th->th_hsize)
177 flex_die (_("pad64 failed"));
183 /** Write this table.
184 * @param out the file writer
185 * @param td table data to be written
186 * @return -1 on error, or bytes written on success.
188 int yytbl_data_fwrite (struct yytbl_writer *wr, struct yytbl_data *td)
191 flex_int32_t bwritten = 0;
192 flex_int32_t i, total_len;
195 if ((rv = yytbl_write16 (wr, td->td_id)) < 0)
199 if ((rv = yytbl_write16 (wr, td->td_flags)) < 0)
203 if ((rv = yytbl_write32 (wr, td->td_hilen)) < 0)
207 if ((rv = yytbl_write32 (wr, td->td_lolen)) < 0)
211 total_len = yytbl_calc_total_len (td);
212 for (i = 0; i < total_len; i++) {
213 switch (YYTDFLAGS2BYTES (td->td_flags)) {
214 case sizeof (flex_int8_t):
215 rv = yytbl_write8 (wr, yytbl_data_geti (td, i));
217 case sizeof (flex_int16_t):
218 rv = yytbl_write16 (wr, yytbl_data_geti (td, i));
220 case sizeof (flex_int32_t):
221 rv = yytbl_write32 (wr, yytbl_data_geti (td, i));
224 flex_die (_("invalid td_flags detected"));
227 flex_die (_("error while writing tables"));
234 if (bwritten != (int) (12 + total_len * YYTDFLAGS2BYTES (td->td_flags))) {
235 flex_die (_("insanity detected"));
240 if ((rv = yytbl_write_pad64 (wr)) < 0) {
241 flex_die (_("pad64 failed"));
246 /* Now go back and update the th_hsize member */
247 if (fgetpos (wr->out, &pos) != 0
248 || fsetpos (wr->out, &(wr->th_ssize_pos)) != 0
249 || yytbl_write32 (wr, wr->total_written) < 0
250 || fsetpos (wr->out, &pos)) {
251 flex_die (_("get|set|fwrite32 failed"));
255 /* Don't count the int we just wrote. */
256 wr->total_written -= sizeof (flex_int32_t);
261 * @param wr the table writer
262 * @param v data to be written
263 * @param len number of bytes
264 * @return -1 on error. number of bytes written on success.
266 int yytbl_writen (struct yytbl_writer *wr, void *v, flex_int32_t len)
270 rv = fwrite (v, 1, len, wr->out);
273 wr->total_written += len;
277 /** Write four bytes in network byte order
278 * @param wr the table writer
279 * @param v a dword in host byte order
280 * @return -1 on error. number of bytes written on success.
282 int yytbl_write32 (struct yytbl_writer *wr, flex_uint32_t v)
288 bytes = sizeof (flex_uint32_t);
289 rv = fwrite (&vnet, bytes, 1, wr->out);
292 wr->total_written += bytes;
296 /** Write two bytes in network byte order.
297 * @param wr the table writer
298 * @param v a word in host byte order
299 * @return -1 on error. number of bytes written on success.
301 int yytbl_write16 (struct yytbl_writer *wr, flex_uint16_t v)
307 bytes = sizeof (flex_uint16_t);
308 rv = fwrite (&vnet, bytes, 1, wr->out);
311 wr->total_written += bytes;
316 * @param wr the table writer
317 * @param v the value to be written
318 * @return -1 on error. number of bytes written on success.
320 int yytbl_write8 (struct yytbl_writer *wr, flex_uint8_t v)
324 bytes = sizeof (flex_uint8_t);
325 rv = fwrite (&v, bytes, 1, wr->out);
328 wr->total_written += bytes;
333 /** Extract data element [i][j] from array data tables.
334 * @param tbl data table
335 * @param i index into higher dimension array. i should be zero for one-dimensional arrays.
336 * @param j index into lower dimension array.
337 * @param k index into struct, must be 0 or 1. Only valid for YYTD_ID_TRANSITION table
338 * @return data[i][j + k]
340 static flex_int32_t yytbl_data_getijk (const struct yytbl_data *tbl, int i,
348 switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
349 case sizeof (flex_int8_t):
350 return ((flex_int8_t *) (tbl->td_data))[(i * lo + j) * (k + 1) +
352 case sizeof (flex_int16_t):
353 return ((flex_int16_t *) (tbl->td_data))[(i * lo + j) * (k +
356 case sizeof (flex_int32_t):
357 return ((flex_int32_t *) (tbl->td_data))[(i * lo + j) * (k +
361 flex_die (_("invalid td_flags detected"));
368 /** Extract data element [i] from array data tables treated as a single flat array of integers.
369 * Be careful for 2-dimensional arrays or for YYTD_ID_TRANSITION, which is an array
371 * @param tbl data table
372 * @param i index into array.
375 static flex_int32_t yytbl_data_geti (const struct yytbl_data *tbl, int i)
378 switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
379 case sizeof (flex_int8_t):
380 return ((flex_int8_t *) (tbl->td_data))[i];
381 case sizeof (flex_int16_t):
382 return ((flex_int16_t *) (tbl->td_data))[i];
383 case sizeof (flex_int32_t):
384 return ((flex_int32_t *) (tbl->td_data))[i];
386 flex_die (_("invalid td_flags detected"));
392 /** Set data element [i] in array data tables treated as a single flat array of integers.
393 * Be careful for 2-dimensional arrays or for YYTD_ID_TRANSITION, which is an array
395 * @param tbl data table
396 * @param i index into array.
397 * @param newval new value for data[i]
399 static void yytbl_data_seti (const struct yytbl_data *tbl, int i,
403 switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
404 case sizeof (flex_int8_t):
405 ((flex_int8_t *) (tbl->td_data))[i] = (flex_int8_t) newval;
407 case sizeof (flex_int16_t):
408 ((flex_int16_t *) (tbl->td_data))[i] = (flex_int16_t) newval;
410 case sizeof (flex_int32_t):
411 ((flex_int32_t *) (tbl->td_data))[i] = (flex_int32_t) newval;
414 flex_die (_("invalid td_flags detected"));
419 /** Calculate the number of bytes needed to hold the largest
420 * absolute value in this data array.
421 * @param tbl the data table
422 * @return sizeof(n) where n in {flex_int8_t, flex_int16_t, flex_int32_t}
424 static size_t min_int_size (struct yytbl_data *tbl)
426 flex_uint32_t i, total_len;
427 flex_int32_t max = 0;
429 total_len = yytbl_calc_total_len (tbl);
431 for (i = 0; i < total_len; i++) {
434 n = abs (yytbl_data_geti (tbl, i));
441 return sizeof (flex_int8_t);
442 else if (max <= INT16_MAX)
443 return sizeof (flex_int16_t);
445 return sizeof (flex_int32_t);
448 /** Transform data to smallest possible of (int32, int16, int8).
449 * For example, we may have generated an int32 array due to user options
450 * (e.g., %option align), but if the maximum value in that array
451 * is 80 (for example), then we can serialize it with only 1 byte per int.
452 * This is NOT the same as compressed DFA tables. We're just trying
453 * to save storage space here.
455 * @param tbl the table to be compressed
457 void yytbl_data_compress (struct yytbl_data *tbl)
459 flex_int32_t i, newsz, total_len;
460 struct yytbl_data newtbl;
462 yytbl_data_init (&newtbl, tbl->td_id);
463 newtbl.td_hilen = tbl->td_hilen;
464 newtbl.td_lolen = tbl->td_lolen;
465 newtbl.td_flags = tbl->td_flags;
467 newsz = min_int_size (tbl);
470 if (newsz == (int) YYTDFLAGS2BYTES (tbl->td_flags))
471 /* No change in this table needed. */
474 if (newsz > (int) YYTDFLAGS2BYTES (tbl->td_flags)) {
475 flex_die (_("detected negative compression"));
479 total_len = yytbl_calc_total_len (tbl);
480 newtbl.td_data = calloc (total_len, newsz);
482 TFLAGS_CLRDATA (newtbl.td_flags) | BYTES2TFLAG (newsz);
484 for (i = 0; i < total_len; i++) {
487 g = yytbl_data_geti (tbl, i);
488 yytbl_data_seti (&newtbl, i, g);
492 /* Now copy over the old table */
497 /* vim:set noexpandtab cindent tabstop=8 softtabstop=0 shiftwidth=8 textwidth=0: */