indent(1): Support "f" and "F" floating constant suffixes.
[freebsd-src.git] / contrib / flex / tables.c
blobf3f056faedaca125264a98bb65e427d46ba5316f
1 /* tables.c - tables serialization code
3 * Copyright (c) 1990 The Regents of the University of California.
4 * All rights reserved.
6 * This code is derived from software contributed to Berkeley by
7 * Vern Paxson.
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
17 * are met:
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
32 * PURPOSE.
36 #include "flexdef.h"
37 #include "tables.h"
39 /** Convert size_t to t_flag.
40 * @param n in {1,2,4}
41 * @return YYTD_DATA*.
43 #define BYTES2TFLAG(n)\
44 (((n) == sizeof(flex_int8_t))\
45 ? YYTD_DATA8\
46 :(((n)== sizeof(flex_int16_t))\
47 ? YYTD_DATA16\
48 : YYTD_DATA32))
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 /* XXX Not used
61 static flex_int32_t yytbl_data_getijk (const struct yytbl_data *tbl, int i,
62 int j, int k);
66 /** Initialize the table writer.
67 * @param wr an uninitialized writer
68 * @param the output file
69 * @return 0 on success
71 int yytbl_writer_init (struct yytbl_writer *wr, FILE * out)
73 wr->out = out;
74 wr->total_written = 0;
75 return 0;
78 /** Initialize a table header.
79 * @param th The uninitialized structure
80 * @param version_str the version string
81 * @param name the name of this table set
83 int yytbl_hdr_init (struct yytbl_hdr *th, const char *version_str,
84 const char *name)
86 memset (th, 0, sizeof (struct yytbl_hdr));
88 th->th_magic = YYTBL_MAGIC;
89 th->th_hsize = 14 + strlen (version_str) + 1 + strlen (name) + 1;
90 th->th_hsize += yypad64 (th->th_hsize);
91 th->th_ssize = 0; // Not known at this point.
92 th->th_flags = 0;
93 th->th_version = copy_string (version_str);
94 th->th_name = copy_string (name);
95 return 0;
98 /** Allocate and initialize a table data structure.
99 * @param tbl a pointer to an uninitialized table
100 * @param id the table identifier
101 * @return 0 on success
103 int yytbl_data_init (struct yytbl_data *td, enum yytbl_id id)
106 memset (td, 0, sizeof (struct yytbl_data));
107 td->td_id = id;
108 td->td_flags = YYTD_DATA32;
109 return 0;
112 /** Clean up table and data array.
113 * @param td will be destroyed
114 * @return 0 on success
116 int yytbl_data_destroy (struct yytbl_data *td)
118 if (td->td_data)
119 free (td->td_data);
120 td->td_data = 0;
121 free (td);
122 return 0;
125 /** Write enough padding to bring the file pointer to a 64-bit boundary. */
126 static int yytbl_write_pad64 (struct yytbl_writer *wr)
128 int pad, bwritten = 0;
130 pad = yypad64 (wr->total_written);
131 while (pad-- > 0)
132 if (yytbl_write8 (wr, 0) < 0)
133 return -1;
134 else
135 bwritten++;
136 return bwritten;
139 /** write the header.
140 * @param out the output stream
141 * @param th table header to be written
142 * @return -1 on error, or bytes written on success.
144 int yytbl_hdr_fwrite (struct yytbl_writer *wr, const struct yytbl_hdr *th)
146 int sz, rv;
147 int bwritten = 0;
149 if (yytbl_write32 (wr, th->th_magic) < 0
150 || yytbl_write32 (wr, th->th_hsize) < 0)
151 flex_die (_("th_magic|th_hsize write32 failed"));
152 bwritten += 8;
154 if (fgetpos (wr->out, &(wr->th_ssize_pos)) != 0)
155 flex_die (_("fgetpos failed"));
157 if (yytbl_write32 (wr, th->th_ssize) < 0
158 || yytbl_write16 (wr, th->th_flags) < 0)
159 flex_die (_("th_ssize|th_flags write failed"));
160 bwritten += 6;
162 sz = strlen (th->th_version) + 1;
163 if ((rv = yytbl_writen (wr, th->th_version, sz)) != sz)
164 flex_die (_("th_version writen failed"));
165 bwritten += rv;
167 sz = strlen (th->th_name) + 1;
168 if ((rv = yytbl_writen (wr, th->th_name, sz)) != sz)
169 flex_die (_("th_name writen failed"));
170 bwritten += rv;
172 /* add padding */
173 if ((rv = yytbl_write_pad64 (wr)) < 0)
174 flex_die (_("pad64 failed"));
175 bwritten += rv;
177 /* Sanity check */
178 if (bwritten != (int) th->th_hsize)
179 flex_die (_("pad64 failed"));
181 return bwritten;
185 /** Write this table.
186 * @param out the file writer
187 * @param td table data to be written
188 * @return -1 on error, or bytes written on success.
190 int yytbl_data_fwrite (struct yytbl_writer *wr, struct yytbl_data *td)
192 int rv;
193 flex_int32_t bwritten = 0;
194 flex_int32_t i, total_len;
195 fpos_t pos;
197 if ((rv = yytbl_write16 (wr, td->td_id)) < 0)
198 return -1;
199 bwritten += rv;
201 if ((rv = yytbl_write16 (wr, td->td_flags)) < 0)
202 return -1;
203 bwritten += rv;
205 if ((rv = yytbl_write32 (wr, td->td_hilen)) < 0)
206 return -1;
207 bwritten += rv;
209 if ((rv = yytbl_write32 (wr, td->td_lolen)) < 0)
210 return -1;
211 bwritten += rv;
213 total_len = yytbl_calc_total_len (td);
214 for (i = 0; i < total_len; i++) {
215 switch (YYTDFLAGS2BYTES (td->td_flags)) {
216 case sizeof (flex_int8_t):
217 rv = yytbl_write8 (wr, yytbl_data_geti (td, i));
218 break;
219 case sizeof (flex_int16_t):
220 rv = yytbl_write16 (wr, yytbl_data_geti (td, i));
221 break;
222 case sizeof (flex_int32_t):
223 rv = yytbl_write32 (wr, yytbl_data_geti (td, i));
224 break;
225 default:
226 flex_die (_("invalid td_flags detected"));
228 if (rv < 0) {
229 flex_die (_("error while writing tables"));
230 return -1;
232 bwritten += rv;
235 /* Sanity check */
236 if (bwritten != (int) (12 + total_len * YYTDFLAGS2BYTES (td->td_flags))) {
237 flex_die (_("insanity detected"));
238 return -1;
241 /* add padding */
242 if ((rv = yytbl_write_pad64 (wr)) < 0) {
243 flex_die (_("pad64 failed"));
244 return -1;
246 bwritten += rv;
248 /* Now go back and update the th_hsize member */
249 if (fgetpos (wr->out, &pos) != 0
250 || fsetpos (wr->out, &(wr->th_ssize_pos)) != 0
251 || yytbl_write32 (wr, wr->total_written) < 0
252 || fsetpos (wr->out, &pos)) {
253 flex_die (_("get|set|fwrite32 failed"));
254 return -1;
256 else
257 /* Don't count the int we just wrote. */
258 wr->total_written -= sizeof (flex_int32_t);
259 return bwritten;
262 /** Write n bytes.
263 * @param wr the table writer
264 * @param v data to be written
265 * @param len number of bytes
266 * @return -1 on error. number of bytes written on success.
268 int yytbl_writen (struct yytbl_writer *wr, void *v, flex_int32_t len)
270 int rv;
272 rv = fwrite (v, 1, len, wr->out);
273 if (rv != len)
274 return -1;
275 wr->total_written += len;
276 return len;
279 /** Write four bytes in network byte order
280 * @param wr the table writer
281 * @param v a dword in host byte order
282 * @return -1 on error. number of bytes written on success.
284 int yytbl_write32 (struct yytbl_writer *wr, flex_uint32_t v)
286 flex_uint32_t vnet;
287 size_t bytes, rv;
289 vnet = htonl (v);
290 bytes = sizeof (flex_uint32_t);
291 rv = fwrite (&vnet, bytes, 1, wr->out);
292 if (rv != 1)
293 return -1;
294 wr->total_written += bytes;
295 return bytes;
298 /** Write two bytes in network byte order.
299 * @param wr the table writer
300 * @param v a word in host byte order
301 * @return -1 on error. number of bytes written on success.
303 int yytbl_write16 (struct yytbl_writer *wr, flex_uint16_t v)
305 flex_uint16_t vnet;
306 size_t bytes, rv;
308 vnet = htons (v);
309 bytes = sizeof (flex_uint16_t);
310 rv = fwrite (&vnet, bytes, 1, wr->out);
311 if (rv != 1)
312 return -1;
313 wr->total_written += bytes;
314 return bytes;
317 /** Write a byte.
318 * @param wr the table writer
319 * @param v the value to be written
320 * @return -1 on error. number of bytes written on success.
322 int yytbl_write8 (struct yytbl_writer *wr, flex_uint8_t v)
324 size_t bytes, rv;
326 bytes = sizeof (flex_uint8_t);
327 rv = fwrite (&v, bytes, 1, wr->out);
328 if (rv != 1)
329 return -1;
330 wr->total_written += bytes;
331 return bytes;
335 /* XXX Not Used */
336 #if 0
337 /** Extract data element [i][j] from array data tables.
338 * @param tbl data table
339 * @param i index into higher dimension array. i should be zero for one-dimensional arrays.
340 * @param j index into lower dimension array.
341 * @param k index into struct, must be 0 or 1. Only valid for YYTD_ID_TRANSITION table
342 * @return data[i][j + k]
344 static flex_int32_t yytbl_data_getijk (const struct yytbl_data *tbl, int i,
345 int j, int k)
347 flex_int32_t lo;
349 k %= 2;
350 lo = tbl->td_lolen;
352 switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
353 case sizeof (flex_int8_t):
354 return ((flex_int8_t *) (tbl->td_data))[(i * lo + j) * (k + 1) +
356 case sizeof (flex_int16_t):
357 return ((flex_int16_t *) (tbl->td_data))[(i * lo + j) * (k +
358 1) +
360 case sizeof (flex_int32_t):
361 return ((flex_int32_t *) (tbl->td_data))[(i * lo + j) * (k +
362 1) +
364 default:
365 flex_die (_("invalid td_flags detected"));
366 break;
369 return 0;
371 #endif /* Not used */
373 /** Extract data element [i] from array data tables treated as a single flat array of integers.
374 * Be careful for 2-dimensional arrays or for YYTD_ID_TRANSITION, which is an array
375 * of structs.
376 * @param tbl data table
377 * @param i index into array.
378 * @return data[i]
380 static flex_int32_t yytbl_data_geti (const struct yytbl_data *tbl, int i)
383 switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
384 case sizeof (flex_int8_t):
385 return ((flex_int8_t *) (tbl->td_data))[i];
386 case sizeof (flex_int16_t):
387 return ((flex_int16_t *) (tbl->td_data))[i];
388 case sizeof (flex_int32_t):
389 return ((flex_int32_t *) (tbl->td_data))[i];
390 default:
391 flex_die (_("invalid td_flags detected"));
392 break;
394 return 0;
397 /** Set data element [i] in array data tables treated as a single flat array of integers.
398 * Be careful for 2-dimensional arrays or for YYTD_ID_TRANSITION, which is an array
399 * of structs.
400 * @param tbl data table
401 * @param i index into array.
402 * @param newval new value for data[i]
404 static void yytbl_data_seti (const struct yytbl_data *tbl, int i,
405 flex_int32_t newval)
408 switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
409 case sizeof (flex_int8_t):
410 ((flex_int8_t *) (tbl->td_data))[i] = (flex_int8_t) newval;
411 break;
412 case sizeof (flex_int16_t):
413 ((flex_int16_t *) (tbl->td_data))[i] = (flex_int16_t) newval;
414 break;
415 case sizeof (flex_int32_t):
416 ((flex_int32_t *) (tbl->td_data))[i] = (flex_int32_t) newval;
417 break;
418 default:
419 flex_die (_("invalid td_flags detected"));
420 break;
424 /** Calculate the number of bytes needed to hold the largest
425 * absolute value in this data array.
426 * @param tbl the data table
427 * @return sizeof(n) where n in {flex_int8_t, flex_int16_t, flex_int32_t}
429 static size_t min_int_size (struct yytbl_data *tbl)
431 flex_uint32_t i, total_len;
432 flex_int32_t max = 0;
434 total_len = yytbl_calc_total_len (tbl);
436 for (i = 0; i < total_len; i++) {
437 flex_int32_t n;
439 n = abs (yytbl_data_geti (tbl, i));
441 if (n > max)
442 max = n;
445 if (max <= INT8_MAX)
446 return sizeof (flex_int8_t);
447 else if (max <= INT16_MAX)
448 return sizeof (flex_int16_t);
449 else
450 return sizeof (flex_int32_t);
453 /** Transform data to smallest possible of (int32, int16, int8).
454 * For example, we may have generated an int32 array due to user options
455 * (e.g., %option align), but if the maximum value in that array
456 * is 80 (for example), then we can serialize it with only 1 byte per int.
457 * This is NOT the same as compressed DFA tables. We're just trying
458 * to save storage space here.
460 * @param tbl the table to be compressed
462 void yytbl_data_compress (struct yytbl_data *tbl)
464 flex_int32_t i, newsz, total_len;
465 struct yytbl_data newtbl;
467 yytbl_data_init (&newtbl, tbl->td_id);
468 newtbl.td_hilen = tbl->td_hilen;
469 newtbl.td_lolen = tbl->td_lolen;
470 newtbl.td_flags = tbl->td_flags;
472 newsz = min_int_size (tbl);
475 if (newsz == (int) YYTDFLAGS2BYTES (tbl->td_flags))
476 /* No change in this table needed. */
477 return;
479 if (newsz > (int) YYTDFLAGS2BYTES (tbl->td_flags)) {
480 flex_die (_("detected negative compression"));
481 return;
484 total_len = yytbl_calc_total_len (tbl);
485 newtbl.td_data = calloc (total_len, newsz);
486 newtbl.td_flags =
487 TFLAGS_CLRDATA (newtbl.td_flags) | BYTES2TFLAG (newsz);
489 for (i = 0; i < total_len; i++) {
490 flex_int32_t g;
492 g = yytbl_data_geti (tbl, i);
493 yytbl_data_seti (&newtbl, i, g);
497 /* Now copy over the old table */
498 free (tbl->td_data);
499 *tbl = newtbl;
502 /* vim:set noexpandtab cindent tabstop=8 softtabstop=0 shiftwidth=8 textwidth=0: */