00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 #include "wsint.h"
00072 #include "ws.h"
00073 #include "wsstree.h"
00074 #include "wsasm.h"
00075
00076
00077
00078 #define WS_CHECK_COMPILE_ERROR() \
00079 do { \
00080 if (compiler->errors != 0) { \
00081 if (compiler->errors & WS_ERROR_B_MEMORY) \
00082 result = WS_ERROR_OUT_OF_MEMORY; \
00083 else if (compiler->errors & WS_ERROR_B_SYNTAX) \
00084 result = WS_ERROR_SYNTAX; \
00085 else if (compiler->errors & WS_ERROR_B_SEMANTIC) \
00086 result = WS_ERROR_SEMANTIC; \
00087 else \
00088 \
00089 result = WS_ERROR; \
00090 goto out; \
00091 } \
00092 } while (0);
00093
00094
00095
00096
00097 static struct
00098 {
00099 WsResult code;
00100 char *description;
00101 } result_codes[] = {
00102 { WS_OK, "success" },
00103 { WS_ERROR_OUT_OF_MEMORY, "out of memory" },
00104 { WS_ERROR_SYNTAX, "syntax error" },
00105 { WS_ERROR_SEMANTIC, "compile error" },
00106 { WS_ERROR_IO, "IO error" },
00107 { WS_ERROR, "error" },
00108
00109 { 0, NULL },
00110 };
00111
00112
00113
00114
00115
00116
00117
00118 static WsResult compile_stream(WsCompilerPtr compiler,
00119 const char *input_name, WsStream *input,
00120 unsigned char **output_return,
00121 size_t *output_len_return);
00122
00123
00124
00125
00126 static void std_io(const char *data, size_t len, void *context);
00127
00128
00129
00130
00131 static int sort_functions_cmp(const void *a, const void *b);
00132
00133
00134
00135 WsCompilerPtr ws_create(WsCompilerParams *params)
00136 {
00137 WsCompilerPtr compiler = ws_calloc(1, sizeof(*compiler));
00138
00139 if (compiler == NULL)
00140 return NULL;
00141
00142
00143 if (params)
00144 compiler->params = *params;
00145
00146
00147
00148 compiler->magic = COMPILER_MAGIC;
00149
00150 if (compiler->params.stdout_cb == NULL) {
00151 compiler->params.stdout_cb = std_io;
00152 compiler->params.stdout_cb_context = stdout;
00153 }
00154 if (compiler->params.stderr_cb == NULL) {
00155 compiler->params.stderr_cb = std_io;
00156 compiler->params.stderr_cb_context = stderr;
00157 }
00158
00159 return compiler;
00160 }
00161
00162
00163 void ws_destroy(WsCompilerPtr compiler)
00164 {
00165 if (compiler == NULL)
00166 return;
00167
00168 ws_free(compiler);
00169
00170 #if WS_MEM_DEBUG
00171 if (ws_has_leaks())
00172 ws_dump_blocks();
00173 #endif
00174 }
00175
00176
00177 WsResult ws_compile_file(WsCompilerPtr compiler, const char *input_name,
00178 FILE *input, FILE *output)
00179 {
00180 WsResult result;
00181 WsStream *stream;
00182 unsigned char *bc;
00183 size_t bc_len;
00184
00185
00186 stream = ws_stream_new_file(input, WS_FALSE, WS_FALSE);
00187 if (stream == NULL)
00188 return WS_ERROR_OUT_OF_MEMORY;
00189
00190 result = compile_stream(compiler, input_name, stream, &bc, &bc_len);
00191
00192 ws_stream_close(stream);
00193
00194 if (result == WS_OK) {
00195
00196 if (fwrite(bc, 1, bc_len, output) != bc_len)
00197 result = WS_ERROR_IO;
00198
00199 ws_bc_data_free(bc);
00200 }
00201
00202 return result;
00203 }
00204
00205
00206 WsResult ws_compile_data(WsCompilerPtr compiler, const char *input_name,
00207 const unsigned char *input, size_t input_len,
00208 unsigned char **output_return,
00209 size_t *output_len_return)
00210 {
00211 WsResult result;
00212 WsStream *stream;
00213
00214
00215 stream = ws_stream_new_data_input(input, input_len);
00216 if (stream == NULL)
00217 return WS_ERROR_OUT_OF_MEMORY;
00218
00219 result = compile_stream(compiler, input_name, stream, output_return,
00220 output_len_return);
00221
00222 ws_stream_close(stream);
00223
00224 return result;
00225 }
00226
00227
00228 void ws_free_byte_code(unsigned char *byte_code)
00229 {
00230 ws_bc_data_free(byte_code);
00231 }
00232
00233
00234 const char *ws_result_to_string(WsResult result)
00235 {
00236 int i;
00237
00238 for (i = 0; result_codes[i].description; i++) {
00239 if (result_codes[i].code == result)
00240 return result_codes[i].description;
00241 }
00242
00243 return "unknown result code";
00244 }
00245
00246
00247
00248 WsBool ws_lexer_register_block(WsCompiler *compiler, void *ptr)
00249 {
00250 void **n;
00251
00252 if (ptr == NULL)
00253 return WS_TRUE;
00254
00255 n = ws_realloc(compiler->lexer_active_list,
00256 ((compiler->lexer_active_list_size + 1) * sizeof(void *)));
00257 if (n == NULL)
00258 return WS_FALSE;
00259
00260 compiler->lexer_active_list = n;
00261 compiler->lexer_active_list[compiler->lexer_active_list_size++] = ptr;
00262
00263 return WS_TRUE;
00264 }
00265
00266
00267 WsBool ws_lexer_register_utf8(WsCompiler *compiler, WsUtf8String *string)
00268 {
00269 if (!ws_lexer_register_block(compiler, string))
00270 return WS_FALSE;
00271
00272 if (!ws_lexer_register_block(compiler, string->data)) {
00273 compiler->lexer_active_list_size--;
00274 return WS_FALSE;
00275 }
00276
00277 return WS_TRUE;
00278 }
00279
00280
00281 void ws_lexer_free_block(WsCompiler *compiler, void *ptr)
00282 {
00283 int i;
00284
00285 if (ptr == NULL)
00286 return;
00287
00288 for (i = compiler->lexer_active_list_size - 1; i >= 0; i--) {
00289 if (compiler->lexer_active_list[i] == ptr) {
00290 memmove(&compiler->lexer_active_list[i],
00291 &compiler->lexer_active_list[i + 1],
00292 (compiler->lexer_active_list_size - i - 1) * sizeof(void *));
00293 compiler->lexer_active_list_size--;
00294
00295 ws_free(ptr);
00296 return;
00297 }
00298 }
00299
00300 ws_fatal("ws_lexer_free_block(): unknown block 0x%lx",
00301 (unsigned long) ptr);
00302 }
00303
00304
00305 void ws_lexer_free_utf8(WsCompiler *compiler, WsUtf8String *string)
00306 {
00307 if (string == NULL)
00308 return;
00309
00310 ws_lexer_free_block(compiler, string->data);
00311 ws_lexer_free_block(compiler, string);
00312 }
00313
00314
00315
00316 static WsResult compile_stream(WsCompilerPtr compiler, const char *input_name,
00317 WsStream *input, unsigned char **output_return,
00318 size_t *output_len_return)
00319 {
00320 WsResult result = WS_OK;
00321 WsUInt32 i;
00322 WsListItem *li;
00323 WsUInt8 findex;
00324 WsUInt8 num_locals;
00325 WsBcStringEncoding string_encoding = WS_BC_STRING_ENC_UTF8;
00326
00327
00328
00329 compiler->linenum = 1;
00330 compiler->input_name = input_name;
00331
00332 compiler->num_errors = 0;
00333 compiler->num_warnings = 0;
00334 compiler->num_extern_functions = 0;
00335 compiler->num_local_functions = 0;
00336 compiler->errors = 0;
00337 compiler->last_syntax_error_line = 0;
00338
00339
00340
00341 compiler->pool_stree = ws_f_create(1024 * 1024);
00342 if (compiler->pool_stree == NULL) {
00343 result = WS_ERROR_OUT_OF_MEMORY;
00344 goto out;
00345 }
00346
00347
00348
00349 compiler->pragma_use_hash = ws_pragma_use_hash_create();
00350 if (compiler->pragma_use_hash == NULL) {
00351 result = WS_ERROR_OUT_OF_MEMORY;
00352 goto out;
00353 }
00354
00355 compiler->functions_hash = ws_function_hash_create();
00356 if (compiler->functions_hash == NULL) {
00357 result = WS_ERROR_OUT_OF_MEMORY;
00358 goto out;
00359 }
00360
00361
00362
00363 if (compiler->params.use_latin1_strings)
00364 string_encoding = WS_BC_STRING_ENC_ISO_8859_1;
00365
00366 compiler->bc = ws_bc_alloc(string_encoding);
00367 if (compiler->bc == NULL) {
00368 result = WS_ERROR_OUT_OF_MEMORY;
00369 goto out;
00370 }
00371
00372
00373 compiler->input = input;
00374
00375
00376 #if WS_DEBUG
00377 global_compiler = compiler;
00378 #endif
00379
00380 ws_yy_parse(compiler);
00381
00382
00383
00384 {
00385 size_t j;
00386
00387 for (j = 0; j < compiler->lexer_active_list_size; j++)
00388 ws_free(compiler->lexer_active_list[j]);
00389 ws_free(compiler->lexer_active_list);
00390
00391 compiler->lexer_active_list = NULL;
00392 }
00393
00394 WS_CHECK_COMPILE_ERROR();
00395
00396
00397 if (!compiler->params.no_opt_sort_bc_functions
00398 && compiler->num_functions > 7) {
00399 WsUInt32 i;
00400
00401 ws_info(compiler, "optimize: sorting functions");
00402
00403
00404 for (i = 0; i < compiler->num_functions; i++) {
00405 WsFunctionHash *fh = ws_function_hash(compiler,
00406 compiler->functions[i].name);
00407 compiler->functions[i].usage_count = fh->usage_count;
00408 }
00409
00410
00411 qsort(compiler->functions, compiler->num_functions,
00412 sizeof(compiler->functions[0]), sort_functions_cmp);
00413
00414
00415 for (i = 0; i < compiler->num_functions; i++) {
00416 WsFunctionHash *fh = ws_function_hash(compiler,
00417 compiler->functions[i].name);
00418 compiler->functions[i].findex = i;
00419 fh->findex = i;
00420 }
00421 }
00422
00423
00424 for (i = 0; i < compiler->num_functions; i++) {
00425 WsFunction *func = &compiler->functions[i];
00426
00427 ws_info(compiler, "linearizing function `%s'...", func->name);
00428
00429 compiler->pool_asm = ws_f_create(100 * 1024);
00430 if (compiler->pool_asm == NULL) {
00431 result = WS_ERROR_OUT_OF_MEMORY;
00432 goto out;
00433 }
00434
00435 compiler->next_label = 0;
00436 compiler->asm_head = compiler->asm_tail = NULL;
00437
00438
00439 compiler->next_vindex = 0;
00440 compiler->variables_hash = ws_variable_hash_create();
00441 if (compiler->variables_hash == NULL) {
00442 result = WS_ERROR_OUT_OF_MEMORY;
00443 goto out;
00444 }
00445
00446
00447 for (li = func->params->head; li; li = li->next) {
00448 WsFormalParm *parm = li->data;
00449
00450 ws_variable_define(compiler, parm->line, WS_FALSE, parm->name);
00451 }
00452
00453 WS_CHECK_COMPILE_ERROR();
00454
00455
00456 for (li = func->block->head; li; li = li->next)
00457 ws_stmt_linearize(compiler, li->data);
00458
00459 WS_CHECK_COMPILE_ERROR();
00460
00461
00462
00463 ws_asm_optimize(compiler);
00464
00465
00466 if (compiler->params.print_symbolic_assembler)
00467 ws_asm_print(compiler);
00468
00469 WS_CHECK_COMPILE_ERROR();
00470
00471
00472
00473 ws_buffer_init(&compiler->byte_code);
00474 ws_asm_linearize(compiler);
00475
00476 WS_CHECK_COMPILE_ERROR();
00477
00478
00479 if (compiler->params.print_assembler)
00480 ws_asm_dasm(compiler, ws_buffer_ptr(&compiler->byte_code),
00481 ws_buffer_len(&compiler->byte_code));
00482
00483
00484 num_locals = compiler->next_vindex - func->params->num_items;
00485
00486
00487 if (!ws_bc_add_function(compiler->bc, &findex,
00488 func->externp ? func->name : NULL,
00489 func->params->num_items,
00490 num_locals,
00491 ws_buffer_len(&compiler->byte_code),
00492 ws_buffer_ptr(&compiler->byte_code))) {
00493 result = WS_ERROR_OUT_OF_MEMORY;
00494 goto out;
00495 }
00496
00497
00498
00499 ws_buffer_uninit(&compiler->byte_code);
00500
00501 ws_hash_destroy(compiler->variables_hash);
00502 compiler->variables_hash = NULL;
00503
00504 ws_f_destroy(compiler->pool_asm);
00505 compiler->pool_asm = NULL;
00506 }
00507
00508
00509 if (!ws_bc_encode(compiler->bc, output_return, output_len_return))
00510 result = WS_ERROR_OUT_OF_MEMORY;
00511
00512 out:
00513
00514
00515
00516 ws_f_destroy(compiler->pool_stree);
00517 compiler->pool_stree = NULL;
00518
00519 ws_hash_destroy(compiler->pragma_use_hash);
00520 compiler->pragma_use_hash = NULL;
00521
00522
00523 for (i = 0; i < compiler->num_functions; i++)
00524 ws_free(compiler->functions[i].name);
00525 ws_free(compiler->functions);
00526
00527 ws_hash_destroy(compiler->functions_hash);
00528 compiler->functions_hash = NULL;
00529
00530 ws_bc_free(compiler->bc);
00531 compiler->bc = NULL;
00532
00533 compiler->input = NULL;
00534
00535 ws_f_destroy(compiler->pool_asm);
00536 compiler->pool_asm = NULL;
00537
00538 ws_hash_destroy(compiler->variables_hash);
00539 compiler->variables_hash = NULL;
00540
00541 ws_buffer_uninit(&compiler->byte_code);
00542
00543
00544 return result;
00545 }
00546
00547
00548 static void std_io(const char *data, size_t len, void *context)
00549 {
00550 fwrite(data, 1, len, (FILE *) context);
00551 }
00552
00553
00554 static int sort_functions_cmp(const void *a, const void *b)
00555 {
00556 WsFunction *fa = (WsFunction *) a;
00557 WsFunction *fb = (WsFunction *) b;
00558
00559 if (fa->usage_count > fb->usage_count)
00560 return -1;
00561 if (fa->usage_count < fb->usage_count)
00562 return 1;
00563
00564 if (fa->findex < fb->findex)
00565 return -1;
00566
00567 return 1;
00568 }
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.