| 194 | # The PBC will be represented as a C string, so this sub builds a table |
| 195 | # of the C representation of each ASCII character, for lookup by ordinal value. |
| 196 | .sub 'generate_encoding_table' |
| 197 | # Use '\%o' for speed, or '\x%02x' for readability |
| 198 | .const string encoding_format = '\%o' |
| 199 | |
| 200 | # The 'sprintf' op requires the arglist to be in an array, even when |
| 201 | # there is only one arg. |
| 202 | .local pmc one_number |
| 203 | one_number = new 'FixedIntegerArray' |
| 204 | set one_number, 1 |
| 205 | |
| 206 | .local pmc coded_strings |
| 207 | coded_strings = new 'FixedStringArray' |
| 208 | set coded_strings, 256 |
| 209 | |
| 210 | .local int index |
| 211 | index = 0 |
| 212 | |
| 213 | next_index: |
| 214 | one_number[0] = index |
| 215 | $S0 = sprintf encoding_format, one_number |
| 216 | coded_strings[index] = $S0 |
| 217 | inc index |
| 218 | if index < 256 goto next_index |
| 219 | |
| 220 | .return (coded_strings) |
| 221 | .end |
| 222 | |
| 223 | # With GCC (and all other known non-Microsoft compilers), huge string constants |
| 224 | # are allowed. We generate a single C string to represent the entire bytecode. |
| 225 | # The get_program_code function simply returns a pointer to the compile-time |
| 226 | # string. |
| 293 | |
| 294 | # On the most limited known version of the Microsoft C compiler, 16KB is the |
| 295 | # maximum size of a string. We generate an array of C strings to represent |
| 296 | # the bytecode; each string is of a fixed size smaller than 16KB. |
| 297 | # The get_program_code() function allocates a block large enough to contain |
| 298 | # the entire bytecode, then fills the block with the C strings at run-time. |
| 299 | .sub 'generate_code_win32' |
| 300 | .param string infile |
| 301 | .local pmc ifh |
| 302 | ifh = open infile, 'r' |
| 303 | unless ifh goto err_infile |
| 304 | |
| 305 | # Since we cannot use the last byte (the end-of-string NULL), the maximum |
| 306 | # block size would be 16384-1. However, we will use 16384-32 (the number |
| 307 | # of bytes in each line) to simplify the code. |
| 308 | .const int line_length = 32 |
| 309 | .const int max_block_size = 16352 |
| 310 | |
| 311 | .local pmc encoding_table |
| 312 | encoding_table = 'generate_encoding_table'() |
| 313 | |
| 314 | .local string codestring |
| 315 | .local int size |
| 316 | codestring = "const char * const program_code_array[] = {\n" |
| 317 | size = 0 |
| 318 | |
| 319 | read_loop: |
| 320 | .local string pbcstring |
| 321 | .local int pbclength |
| 322 | |
| 323 | pbcstring = read ifh, max_block_size |
| 324 | pbclength = length pbcstring |
| 325 | unless pbclength > 0 goto read_done |
| 326 | |
| 327 | # This padding is to keep the memcpy() from ever having to deal with a short block. |
| 328 | pad_to_full_block: |
| 329 | unless pbclength < max_block_size goto end_pad |
| 330 | pbcstring .= "\0" |
| 331 | inc pbclength |
| 332 | goto pad_to_full_block |
| 333 | end_pad: |
| 334 | |
| 335 | if size == 0 goto skip_comma_separating_strings |
| 336 | codestring .= ",\n" |
| 337 | skip_comma_separating_strings: |
| 338 | |
| 339 | |
| 340 | .local int pos |
| 341 | pos = 0 |
| 342 | code_loop: |
| 343 | unless pos < pbclength goto code_done |
| 344 | |
| 345 | $I0 = pos % line_length |
| 346 | unless $I0 == 0 goto skip_line_start_quote |
| 347 | codestring .= ' "' |
| 348 | skip_line_start_quote: |
| 349 | |
| 350 | |
| 351 | $I0 = ord pbcstring, pos |
| 352 | $S0 = encoding_table[$I0] |
| 353 | codestring .= $S0 |
| 354 | inc pos |
| 355 | inc size |
| 356 | |
| 357 | |
| 358 | $I0 = size % line_length |
| 359 | unless $I0 == 0 goto skip_line_end_quote |
| 360 | codestring .= '"' |
| 361 | codestring .= "\n" |
| 362 | skip_line_end_quote: |
| 363 | |
| 364 | goto code_loop |
| 365 | code_done: |
| 366 | goto read_loop |
| 367 | |
| 368 | read_done: |
| 369 | close ifh |
| 370 | |
| 371 | codestring .= ",\nNULL\n" |
| 372 | codestring .= "};\n\n" |
| 373 | |
| 374 | codestring .= "const int bytecode_size = " |
| 375 | $S0 = size |
| 376 | codestring .= $S0 |
| 377 | codestring .= ";\n" |
| 378 | |
| 379 | codestring .= "const int max_block_size = " |
| 380 | $S0 = max_block_size |
| 381 | codestring .= $S0 |
| 382 | codestring .= ";\n" |
| 383 | |
| 384 | $S0 = <<'SUBROUTINE' |
| 385 | const char * get_program_code(void); |
| 386 | const char * get_program_code(void) |
| 387 | { |
| 388 | int i; |
| 389 | char *p, *program_code_in_one_block; |
| 390 | |
| 391 | program_code_in_one_block = malloc( bytecode_size ); |
| 392 | if (!program_code_in_one_block) |
| 393 | return NULL; |
| 394 | |
| 395 | for ( i = 0, p = program_code_in_one_block; program_code_array[i]; i++, p += max_block_size ) |
| 396 | memcpy( p, program_code_array[i], max_block_size ); |
| 397 | |
| 398 | return program_code_in_one_block; |
| 399 | } |
| 400 | SUBROUTINE |
| 401 | codestring .= $S0 |
| 402 | |
| 403 | .return (codestring) |
| 404 | |
| 405 | err_infile: |
| 406 | die "cannot open infile" |
| 407 | .end |
| 408 | |
| 409 | |