filename | src/tools/gendec.c |
changeset | 1084:852412cf56e0 |
prev | 979:2cc7b486ea6c |
next | 1296:30ecee61f811 |
author | nkeynes |
date | Fri Sep 10 08:48:34 2010 +1000 (13 years ago) |
permissions | -rw-r--r-- |
last change | Run the eventq at the end of the time-slice rather than the beginning, so that it runs for the correct period of time when the time-slice finishes early |
file | annotate | diff | log | raw |
nkeynes@359 | 1 | /** |
nkeynes@561 | 2 | * $Id$ |
nkeynes@359 | 3 | * |
nkeynes@359 | 4 | * Parse the instruction and action files and generate an appropriate |
nkeynes@359 | 5 | * instruction decoder. |
nkeynes@359 | 6 | * |
nkeynes@359 | 7 | * Copyright (c) 2005 Nathan Keynes. |
nkeynes@359 | 8 | * |
nkeynes@359 | 9 | * This program is free software; you can redistribute it and/or modify |
nkeynes@359 | 10 | * it under the terms of the GNU General Public License as published by |
nkeynes@359 | 11 | * the Free Software Foundation; either version 2 of the License, or |
nkeynes@359 | 12 | * (at your option) any later version. |
nkeynes@359 | 13 | * |
nkeynes@359 | 14 | * This program is distributed in the hope that it will be useful, |
nkeynes@359 | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
nkeynes@359 | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
nkeynes@359 | 17 | * GNU General Public License for more details. |
nkeynes@359 | 18 | */ |
nkeynes@359 | 19 | |
nkeynes@359 | 20 | #include <stdio.h> |
nkeynes@359 | 21 | #include <stdlib.h> |
nkeynes@359 | 22 | #include <string.h> |
nkeynes@359 | 23 | #include <getopt.h> |
nkeynes@359 | 24 | #include <errno.h> |
nkeynes@359 | 25 | #include <ctype.h> |
nkeynes@359 | 26 | #include <glib/gstrfuncs.h> |
nkeynes@359 | 27 | #include <assert.h> |
nkeynes@359 | 28 | #include "tools/gendec.h" |
nkeynes@359 | 29 | |
nkeynes@359 | 30 | #define DEFAULT_OUT_EXT ".c" |
nkeynes@359 | 31 | |
nkeynes@359 | 32 | const char *ins_filename = NULL; |
nkeynes@359 | 33 | const char *act_filename = NULL; |
nkeynes@359 | 34 | const char *out_filename = NULL; |
nkeynes@359 | 35 | |
nkeynes@359 | 36 | #define GEN_SOURCE 1 |
nkeynes@359 | 37 | #define GEN_TEMPLATE 2 |
nkeynes@359 | 38 | |
nkeynes@359 | 39 | FILE *ins_file, *act_file, *out_file; |
nkeynes@359 | 40 | |
nkeynes@1084 | 41 | char *option_list = "tmho:w"; |
nkeynes@359 | 42 | int gen_mode = GEN_SOURCE; |
nkeynes@1084 | 43 | int emit_warnings = 0; |
nkeynes@1084 | 44 | |
nkeynes@1084 | 45 | struct option longopts[] = { |
nkeynes@1084 | 46 | { "help", no_argument, NULL, 'h' }, |
nkeynes@1084 | 47 | { "output", required_argument, NULL, 'o' }, |
nkeynes@1084 | 48 | { "template", no_argument, NULL, 't' }, |
nkeynes@1084 | 49 | { "warnings", no_argument, NULL, 'w' }, |
nkeynes@1084 | 50 | { NULL, 0, 0, 0 } }; |
nkeynes@359 | 51 | |
nkeynes@969 | 52 | static void usage() { |
nkeynes@1084 | 53 | printf( "Usage: gendec [options] <instruction-file> <action-file> [ -o <output-file> ]\n" ); |
nkeynes@1084 | 54 | printf( "Options:\n" ); |
nkeynes@1084 | 55 | printf( " -h, --help Print this help message\n" ); |
nkeynes@1084 | 56 | printf( " -o, --output=FILE Generate output to the given file\n" ); |
nkeynes@1084 | 57 | printf( " -t, --template Generate a template skeleton instead of an instruction matcher\n" ); |
nkeynes@1084 | 58 | printf( " -w, --warnings Emit warnings when unmatched instructions are found\n" ); |
nkeynes@1084 | 59 | } |
nkeynes@1084 | 60 | |
nkeynes@1084 | 61 | /** |
nkeynes@1084 | 62 | * Check that rules are provided for all actions |
nkeynes@1084 | 63 | */ |
nkeynes@1084 | 64 | static void check_actions( struct ruleset *rules, const actiontoken_t token ) |
nkeynes@1084 | 65 | { |
nkeynes@1084 | 66 | int i; |
nkeynes@1084 | 67 | int warnings = 0; |
nkeynes@1084 | 68 | for( i=0; i<rules->rule_count; i++ ) { |
nkeynes@1084 | 69 | if( token->actions[i].text == NULL ) { |
nkeynes@1084 | 70 | if( warnings == 0 ) { |
nkeynes@1084 | 71 | fprintf( stderr, "In action block starting at line %d of file %s:\n", |
nkeynes@1084 | 72 | token->lineno, token->filename ); |
nkeynes@1084 | 73 | } |
nkeynes@1084 | 74 | fprintf( stderr, "Warning: No action matches rule %d %s\n", i, rules->rules[i]->format ); |
nkeynes@1084 | 75 | warnings++; |
nkeynes@1084 | 76 | } else { |
nkeynes@1084 | 77 | const char *s = token->actions[i].text; |
nkeynes@1084 | 78 | while( *s ) { |
nkeynes@1084 | 79 | if( !isspace(*s) ) |
nkeynes@1084 | 80 | break; |
nkeynes@1084 | 81 | s++; |
nkeynes@1084 | 82 | } |
nkeynes@1084 | 83 | if( !*s ) { |
nkeynes@1084 | 84 | if( warnings == 0 ) { |
nkeynes@1084 | 85 | fprintf( stderr, "In action block starting at line %d of file %s:\n", |
nkeynes@1084 | 86 | token->lineno, token->filename ); |
nkeynes@1084 | 87 | } |
nkeynes@1084 | 88 | fprintf( stderr, "Warning: Empty action for rule %d %s at line %d\n", i, rules->rules[i]->format, |
nkeynes@1084 | 89 | token->actions[i].lineno ); |
nkeynes@1084 | 90 | warnings++; |
nkeynes@1084 | 91 | } |
nkeynes@1084 | 92 | } |
nkeynes@1084 | 93 | } |
nkeynes@359 | 94 | } |
nkeynes@359 | 95 | |
nkeynes@359 | 96 | /** |
nkeynes@359 | 97 | * Find a mask that can be used to split up the given rules |
nkeynes@359 | 98 | */ |
nkeynes@969 | 99 | static uint32_t find_mask( struct ruleset *rules, int ruleidx[], int rule_count, |
nkeynes@736 | 100 | uint32_t input_mask ) |
nkeynes@359 | 101 | { |
nkeynes@359 | 102 | int i; |
nkeynes@359 | 103 | uint32_t mask = rules->rules[ruleidx[0]]->mask; |
nkeynes@359 | 104 | |
nkeynes@359 | 105 | for( i=1; i<rule_count; i++ ) { |
nkeynes@736 | 106 | mask = mask & rules->rules[ruleidx[i]]->mask; |
nkeynes@359 | 107 | } |
nkeynes@359 | 108 | |
nkeynes@359 | 109 | assert( (mask & input_mask) == input_mask ); /* input_mask should always be included in the mask */ |
nkeynes@359 | 110 | |
nkeynes@359 | 111 | return mask & (~input_mask); /* but we don't want to see the input mask again */ |
nkeynes@359 | 112 | } |
nkeynes@359 | 113 | |
nkeynes@969 | 114 | static int get_option_count_for_mask( uint32_t mask ) { |
nkeynes@359 | 115 | int count = 0; |
nkeynes@359 | 116 | |
nkeynes@359 | 117 | while( mask ) { |
nkeynes@736 | 118 | if( mask&1 ) |
nkeynes@736 | 119 | count++; |
nkeynes@736 | 120 | mask >>= 1; |
nkeynes@359 | 121 | } |
nkeynes@359 | 122 | return 1<<count; |
nkeynes@359 | 123 | } |
nkeynes@359 | 124 | |
nkeynes@359 | 125 | int get_bitshift_for_mask( uint32_t mask ) { |
nkeynes@359 | 126 | int shift = 0; |
nkeynes@359 | 127 | while( mask && !(mask&1) ) { |
nkeynes@736 | 128 | shift++; |
nkeynes@736 | 129 | mask >>= 1; |
nkeynes@359 | 130 | } |
nkeynes@359 | 131 | return shift; |
nkeynes@359 | 132 | } |
nkeynes@359 | 133 | |
nkeynes@969 | 134 | static void get_option_values_for_mask( uint32_t *options, |
nkeynes@736 | 135 | uint32_t mask ) |
nkeynes@359 | 136 | { |
nkeynes@359 | 137 | /* This could be a lot smarter. But it's not */ |
nkeynes@359 | 138 | int i; |
nkeynes@359 | 139 | *options = 0; |
nkeynes@359 | 140 | for( i=1; i<=mask; i++ ) { |
nkeynes@736 | 141 | if( (i & mask) > *options ) { |
nkeynes@736 | 142 | options++; |
nkeynes@736 | 143 | *options = (i&mask); |
nkeynes@736 | 144 | } |
nkeynes@359 | 145 | } |
nkeynes@359 | 146 | } |
nkeynes@359 | 147 | |
nkeynes@979 | 148 | static void fprint_indent( const char *action, int depth, FILE *f ) |
nkeynes@359 | 149 | { |
nkeynes@359 | 150 | int spaces = 0, needed = depth*8, i; |
nkeynes@979 | 151 | const char *text = action; |
nkeynes@359 | 152 | |
nkeynes@359 | 153 | /* Determine number of spaces in first line of input */ |
nkeynes@359 | 154 | for( i=0; isspace(action[i]); i++ ) { |
nkeynes@736 | 155 | if( action[i] == '\n' ) { |
nkeynes@736 | 156 | spaces = 0; |
nkeynes@736 | 157 | text = &action[i+1]; |
nkeynes@736 | 158 | } else { |
nkeynes@736 | 159 | spaces++; |
nkeynes@736 | 160 | } |
nkeynes@359 | 161 | } |
nkeynes@359 | 162 | |
nkeynes@359 | 163 | needed -= spaces; |
nkeynes@359 | 164 | fprintf( f, "%*c", needed, ' ' ); |
nkeynes@359 | 165 | for( i=0; text[i] != '\0'; i++ ) { |
nkeynes@736 | 166 | fputc( text[i], f ); |
nkeynes@736 | 167 | if( text[i] == '\n' && text[i+1] != '\0' ) { |
nkeynes@736 | 168 | fprintf( f, "%*c", needed, ' ' ); |
nkeynes@736 | 169 | } |
nkeynes@359 | 170 | } |
nkeynes@359 | 171 | if( text[i-1] != '\n' ) { |
nkeynes@736 | 172 | fprintf( f, "\n" ); |
nkeynes@359 | 173 | } |
nkeynes@359 | 174 | } |
nkeynes@359 | 175 | |
nkeynes@979 | 176 | static void fprint_action( struct rule *rule, const struct action *action, int depth, FILE *f ) |
nkeynes@359 | 177 | { |
nkeynes@359 | 178 | int i; |
nkeynes@359 | 179 | if( action == NULL ) { |
nkeynes@736 | 180 | fprintf( f, "%*cUNIMP(ir); /* %s */\n", depth*8, ' ', rule->format ); |
nkeynes@359 | 181 | } else { |
nkeynes@736 | 182 | fprintf( f, "%*c{ /* %s */", depth*8, ' ', rule->format ); |
nkeynes@736 | 183 | if( rule->operand_count != 0 ) { |
nkeynes@736 | 184 | fprintf( f, "\n%*c", depth*8, ' ' ); |
nkeynes@736 | 185 | for( i=0; i<rule->operand_count; i++ ) { |
nkeynes@736 | 186 | if( rule->operands[i].is_signed ) { |
nkeynes@736 | 187 | fprintf( f, "int32_t %s = SIGNEXT%d", rule->operands[i].name, rule->operands[i].bit_count ); |
nkeynes@736 | 188 | } else { |
nkeynes@736 | 189 | fprintf( f, "uint32_t %s = ", rule->operands[i].name ); |
nkeynes@736 | 190 | } |
nkeynes@736 | 191 | if( rule->operands[i].bit_shift == 0 ) { |
nkeynes@736 | 192 | fprintf( f, "(ir&0x%X)", (1<<(rule->operands[i].bit_count))-1 ); |
nkeynes@736 | 193 | } else { |
nkeynes@736 | 194 | fprintf( f, "((ir>>%d)&0x%X)", rule->operands[i].bit_shift, |
nkeynes@736 | 195 | (1<<(rule->operands[i].bit_count))-1 ); |
nkeynes@736 | 196 | } |
nkeynes@736 | 197 | if( rule->operands[i].left_shift != 0 ) { |
nkeynes@736 | 198 | fprintf( f, "<<%d", rule->operands[i].left_shift ); |
nkeynes@736 | 199 | } |
nkeynes@736 | 200 | fprintf( f, "; " ); |
nkeynes@736 | 201 | } |
nkeynes@736 | 202 | } |
nkeynes@736 | 203 | fputs( "\n", f ); |
nkeynes@979 | 204 | if( action->text && action->text[0] != '\0' ) { |
nkeynes@979 | 205 | fprintf( f, "#line %d \"%s\"\n", action->lineno, action->filename ); |
nkeynes@979 | 206 | fprint_indent( action->text, depth, f ); |
nkeynes@736 | 207 | } |
nkeynes@736 | 208 | fprintf( f, "%*c}\n", depth*8, ' ' ); |
nkeynes@359 | 209 | } |
nkeynes@359 | 210 | } |
nkeynes@359 | 211 | |
nkeynes@979 | 212 | static void split_and_generate( struct ruleset *rules, const struct action *actions, |
nkeynes@736 | 213 | int ruleidx[], int rule_count, int input_mask, |
nkeynes@736 | 214 | int depth, FILE *f ) { |
nkeynes@359 | 215 | uint32_t mask; |
nkeynes@359 | 216 | int i,j; |
nkeynes@359 | 217 | |
nkeynes@359 | 218 | if( rule_count == 0 ) { |
nkeynes@736 | 219 | fprintf( f, "%*cUNDEF(ir);\n", depth*8, ' ' ); |
nkeynes@359 | 220 | } else if( rule_count == 1 ) { |
nkeynes@979 | 221 | fprint_action( rules->rules[ruleidx[0]], &actions[ruleidx[0]], depth, f ); |
nkeynes@359 | 222 | } else { |
nkeynes@359 | 223 | |
nkeynes@736 | 224 | mask = find_mask(rules, ruleidx, rule_count, input_mask); |
nkeynes@736 | 225 | if( mask == 0 ) { /* No matching mask? */ |
nkeynes@736 | 226 | fprintf( stderr, "Error: unable to find a valid bitmask (%d rules, %08X input mask)\n", rule_count, input_mask ); |
nkeynes@736 | 227 | dump_rulesubset( rules, ruleidx, rule_count, stderr ); |
nkeynes@736 | 228 | return; |
nkeynes@736 | 229 | } |
nkeynes@736 | 230 | |
nkeynes@736 | 231 | /* break up the rules into sub-sets, and process each sub-set. |
nkeynes@736 | 232 | * NB: We could do this in one pass at the cost of more complex |
nkeynes@736 | 233 | * data structures. For now though, this keeps it simple |
nkeynes@736 | 234 | */ |
nkeynes@736 | 235 | int option_count = get_option_count_for_mask( mask ); |
nkeynes@736 | 236 | uint32_t options[option_count]; |
nkeynes@736 | 237 | int subruleidx[rule_count]; |
nkeynes@736 | 238 | int subrule_count; |
nkeynes@736 | 239 | int mask_shift = get_bitshift_for_mask( mask ); |
nkeynes@736 | 240 | int has_empty_options = 0; |
nkeynes@736 | 241 | get_option_values_for_mask( options, mask ); |
nkeynes@736 | 242 | |
nkeynes@736 | 243 | if( mask_shift == 0 ) { |
nkeynes@736 | 244 | fprintf( f, "%*cswitch( ir&0x%X ) {\n", depth*8, ' ', mask ); |
nkeynes@736 | 245 | } else { |
nkeynes@736 | 246 | fprintf( f, "%*cswitch( (ir&0x%X) >> %d ) {\n", depth*8, ' ', |
nkeynes@736 | 247 | mask, mask_shift); |
nkeynes@736 | 248 | } |
nkeynes@736 | 249 | for( i=0; i<option_count; i++ ) { |
nkeynes@736 | 250 | subrule_count = 0; |
nkeynes@736 | 251 | for( j=0; j<rule_count; j++ ) { |
nkeynes@736 | 252 | int match = rules->rules[ruleidx[j]]->bits & mask; |
nkeynes@736 | 253 | if( match == options[i] ) { |
nkeynes@736 | 254 | subruleidx[subrule_count++] = ruleidx[j]; |
nkeynes@736 | 255 | } |
nkeynes@736 | 256 | } |
nkeynes@736 | 257 | if( subrule_count == 0 ) { |
nkeynes@736 | 258 | has_empty_options = 1; |
nkeynes@736 | 259 | } else { |
nkeynes@736 | 260 | fprintf( f, "%*ccase 0x%X:\n", depth*8+4, ' ', options[i]>>mask_shift ); |
nkeynes@736 | 261 | split_and_generate( rules, actions, subruleidx, subrule_count, |
nkeynes@736 | 262 | mask|input_mask, depth+1, f ); |
nkeynes@736 | 263 | fprintf( f, "%*cbreak;\n", depth*8+8, ' ' ); |
nkeynes@736 | 264 | } |
nkeynes@736 | 265 | } |
nkeynes@736 | 266 | if( has_empty_options ) { |
nkeynes@824 | 267 | fprintf( f, "%*cdefault:\n%*cUNDEF(ir);\n%*cbreak;\n", |
nkeynes@736 | 268 | depth*8+4, ' ', depth*8+8, ' ', depth*8 + 8, ' ' ); |
nkeynes@736 | 269 | } |
nkeynes@736 | 270 | fprintf( f, "%*c}\n", depth*8, ' ' ); |
nkeynes@359 | 271 | } |
nkeynes@359 | 272 | } |
nkeynes@359 | 273 | |
nkeynes@969 | 274 | static int generate_decoder( struct ruleset *rules, actionfile_t af, FILE *out ) |
nkeynes@359 | 275 | { |
nkeynes@359 | 276 | int ruleidx[rules->rule_count]; |
nkeynes@359 | 277 | int i; |
nkeynes@359 | 278 | |
nkeynes@359 | 279 | for( i=0; i<rules->rule_count; i++ ) { |
nkeynes@736 | 280 | ruleidx[i] = i; |
nkeynes@359 | 281 | } |
nkeynes@359 | 282 | |
nkeynes@948 | 283 | actiontoken_t token = action_file_next(af); |
nkeynes@948 | 284 | while( token->symbol != END ) { |
nkeynes@948 | 285 | if( token->symbol == TEXT ) { |
nkeynes@979 | 286 | fprintf( out, "#line %d \"%s\"\n", token->lineno, token->filename ); |
nkeynes@948 | 287 | fputs( token->text, out ); |
nkeynes@948 | 288 | } else if( token->symbol == ERROR ) { |
nkeynes@948 | 289 | fprintf( stderr, "Error parsing action file" ); |
nkeynes@948 | 290 | return -1; |
nkeynes@948 | 291 | } else { |
nkeynes@1084 | 292 | if( emit_warnings ) { |
nkeynes@1084 | 293 | check_actions( rules, token ); |
nkeynes@1084 | 294 | } |
nkeynes@948 | 295 | split_and_generate( rules, token->actions, ruleidx, rules->rule_count, 0, 1, out ); |
nkeynes@948 | 296 | } |
nkeynes@948 | 297 | token = action_file_next(af); |
nkeynes@948 | 298 | } |
nkeynes@359 | 299 | return 0; |
nkeynes@359 | 300 | } |
nkeynes@359 | 301 | |
nkeynes@969 | 302 | static int generate_template( struct ruleset *rules, actionfile_t af, FILE *out ) |
nkeynes@359 | 303 | { |
nkeynes@359 | 304 | int i; |
nkeynes@948 | 305 | |
nkeynes@948 | 306 | actiontoken_t token = action_file_next(af); |
nkeynes@948 | 307 | while( token->symbol != END ) { |
nkeynes@948 | 308 | if( token->symbol == TEXT ) { |
nkeynes@948 | 309 | fputs( token->text, out ); |
nkeynes@948 | 310 | } else if( token->symbol == ERROR ) { |
nkeynes@948 | 311 | fprintf( stderr, "Error parsing action file" ); |
nkeynes@948 | 312 | return -1; |
nkeynes@948 | 313 | } else { |
nkeynes@948 | 314 | fputs( "%%\n", out ); |
nkeynes@948 | 315 | for( i=0; i<rules->rule_count; i++ ) { |
nkeynes@948 | 316 | fprintf( out, "%s {: %s :}\n", rules->rules[i]->format, |
nkeynes@979 | 317 | token->actions[i].text == NULL ? "" : token->actions[i].text ); |
nkeynes@948 | 318 | } |
nkeynes@948 | 319 | fputs( "%%\n", out ); |
nkeynes@948 | 320 | } |
nkeynes@948 | 321 | token = action_file_next(af); |
nkeynes@359 | 322 | } |
nkeynes@736 | 323 | |
nkeynes@359 | 324 | return 0; |
nkeynes@359 | 325 | } |
nkeynes@420 | 326 | |
nkeynes@420 | 327 | |
nkeynes@420 | 328 | int main( int argc, char *argv[] ) |
nkeynes@420 | 329 | { |
nkeynes@420 | 330 | int opt; |
nkeynes@420 | 331 | |
nkeynes@420 | 332 | /* Parse the command line */ |
nkeynes@420 | 333 | while( (opt = getopt_long( argc, argv, option_list, longopts, NULL )) != -1 ) { |
nkeynes@420 | 334 | switch( opt ) { |
nkeynes@736 | 335 | case 't': |
nkeynes@736 | 336 | gen_mode = GEN_TEMPLATE; |
nkeynes@736 | 337 | break; |
nkeynes@736 | 338 | case 'o': |
nkeynes@736 | 339 | out_filename = optarg; |
nkeynes@736 | 340 | break; |
nkeynes@1084 | 341 | case 'w': |
nkeynes@1084 | 342 | emit_warnings = 1; |
nkeynes@1084 | 343 | break; |
nkeynes@736 | 344 | case 'h': |
nkeynes@736 | 345 | usage(); |
nkeynes@736 | 346 | exit(0); |
nkeynes@736 | 347 | } |
nkeynes@420 | 348 | } |
nkeynes@420 | 349 | if( optind < argc ) { |
nkeynes@736 | 350 | ins_filename = argv[optind++]; |
nkeynes@420 | 351 | } |
nkeynes@420 | 352 | if( optind < argc ) { |
nkeynes@736 | 353 | act_filename = argv[optind++]; |
nkeynes@420 | 354 | } |
nkeynes@420 | 355 | |
nkeynes@420 | 356 | if( optind < argc || ins_filename == NULL || act_filename == NULL ) { |
nkeynes@736 | 357 | usage(); |
nkeynes@736 | 358 | exit(1); |
nkeynes@420 | 359 | } |
nkeynes@736 | 360 | |
nkeynes@420 | 361 | if( out_filename == NULL ) { |
nkeynes@736 | 362 | if( gen_mode == GEN_TEMPLATE ) { |
nkeynes@736 | 363 | out_filename = act_filename; |
nkeynes@736 | 364 | } else { |
nkeynes@736 | 365 | char tmp[strlen(act_filename)+1]; |
nkeynes@736 | 366 | strcpy( tmp, act_filename); |
nkeynes@736 | 367 | char *c = strrchr( tmp, '.' ); |
nkeynes@736 | 368 | if( c != NULL ) { |
nkeynes@736 | 369 | *c = '\0'; |
nkeynes@736 | 370 | } |
nkeynes@736 | 371 | out_filename = g_strconcat( tmp, DEFAULT_OUT_EXT, NULL ); |
nkeynes@736 | 372 | } |
nkeynes@420 | 373 | } |
nkeynes@420 | 374 | |
nkeynes@420 | 375 | /* Open the files */ |
nkeynes@420 | 376 | ins_file = fopen( ins_filename, "ro" ); |
nkeynes@420 | 377 | if( ins_file == NULL ) { |
nkeynes@420 | 378 | fprintf( stderr, "Unable to open '%s' for reading (%s)\n", ins_filename, strerror(errno) ); |
nkeynes@736 | 379 | exit(2); |
nkeynes@420 | 380 | } |
nkeynes@420 | 381 | |
nkeynes@420 | 382 | /* Parse the input */ |
nkeynes@420 | 383 | struct ruleset *rules = parse_ruleset_file( ins_file ); |
nkeynes@420 | 384 | fclose( ins_file ); |
nkeynes@420 | 385 | if( rules == NULL ) { |
nkeynes@736 | 386 | exit(5); |
nkeynes@420 | 387 | } |
nkeynes@948 | 388 | |
nkeynes@948 | 389 | actionfile_t af = action_file_open( act_filename, rules ); |
nkeynes@948 | 390 | if( af == NULL ) { |
nkeynes@948 | 391 | fprintf( stderr, "Unable to open '%s' for reading (%s)\n", act_filename, strerror(errno) ); |
nkeynes@948 | 392 | exit(3); |
nkeynes@420 | 393 | } |
nkeynes@420 | 394 | |
nkeynes@948 | 395 | |
nkeynes@948 | 396 | /* Open the output file */ |
nkeynes@420 | 397 | out_file = fopen( out_filename, "wo" ); |
nkeynes@420 | 398 | if( out_file == NULL ) { |
nkeynes@420 | 399 | fprintf( stderr, "Unable to open '%s' for writing (%s)\n", out_filename, strerror(errno) ); |
nkeynes@736 | 400 | exit(4); |
nkeynes@420 | 401 | } |
nkeynes@736 | 402 | |
nkeynes@420 | 403 | switch( gen_mode ) { |
nkeynes@420 | 404 | case GEN_SOURCE: |
nkeynes@948 | 405 | if( generate_decoder( rules, af, out_file ) != 0 ) { |
nkeynes@736 | 406 | exit(7); |
nkeynes@736 | 407 | } |
nkeynes@736 | 408 | break; |
nkeynes@420 | 409 | case GEN_TEMPLATE: |
nkeynes@948 | 410 | if( generate_template( rules, af, out_file ) != 0 ) { |
nkeynes@736 | 411 | exit(7); |
nkeynes@736 | 412 | } |
nkeynes@736 | 413 | break; |
nkeynes@420 | 414 | } |
nkeynes@948 | 415 | |
nkeynes@948 | 416 | action_file_close(af); |
nkeynes@420 | 417 | fclose( out_file ); |
nkeynes@420 | 418 | return 0; |
nkeynes@420 | 419 | } |
.