|
|
1 //! @file plugin.c 2 //! @author J. Marcel van der Veer 3 4 //! @section Copyright 5 //! 6 //! This file is part of Algol68G - an Algol 68 compiler-interpreter. 7 //! Copyright 2001-2026 J. Marcel van der Veer [algol68g@algol68genie.nl]. 8 9 //! @section License 10 //! 11 //! This program is free software; you can redistribute it and/or modify it 12 //! under the terms of the GNU General Public License as published by the 13 //! Free Software Foundation; either version 3 of the License, or 14 //! (at your option) any later version. 15 //! 16 //! This program is distributed in the hope that it will be useful, but 17 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 //! more details. You should have received a copy of the GNU General Public 20 //! License along with this program. If not, see [http://www.gnu.org/licenses/]. 21 22 //! @section Synopsis 23 //! 24 //! Plugin compiler driver. 25 26 // The plugin compiler generates optimised C routines for many units in an Algol 68 source 27 // program. A68G 1.x contained some general optimised routines. These are 28 // decommissioned in A68G 2.x that dynamically generates routines depending 29 // on the source code. The generated routines are compiled on the fly into a 30 // dynamic library that is linked by the running interpreter, like a plugin. 31 32 // To invoke this code generator specify option --optimise. 33 // Currently the optimiser only considers units that operate on basic modes that are 34 // contained in a single C struct, for instance primitive modes 35 // 36 // INT, REAL, BOOL, CHAR and BITS 37 // 38 // and simple structures of these basic modes, such as 39 // 40 // COMPLEX 41 // 42 // and also (single) references, rows and procedures 43 // 44 // REF MODE, [] MODE, PROC PARAMSETY MODE 45 // 46 // The code generator employs a few simple optimisations like constant folding 47 // and common subexpression elimination when DEREFERENCING or SLICING is 48 // performed; for instance 49 // 50 // x[i + 1] := x[i + 1] + 1 51 // 52 // translates into 53 // 54 // tmp = x[i + 1]; tmp := tmp + 1 55 // 56 // We don't do stuff that is easily recognised by a back end compiler, 57 // for instance symbolic simplification. 58 59 #include "a68g.h" 60 #include "a68g-prelude.h" 61 #include "a68g-genie.h" 62 #include "a68g-listing.h" 63 #include "a68g-optimiser.h" 64 #include "a68g-plugin.h" 65 #include "a68g-transput.h" 66 67 //! @brief Compiler optimisation option string 68 69 char *optimisation_option (void) 70 { 71 switch (OPTION_OPT_LEVEL (&A68G_JOB)) { 72 case OPTIMISE_0: { 73 return "-Og"; 74 } 75 case OPTIMISE_1: { 76 return "-O1"; 77 } 78 case OPTIMISE_2: { 79 return "-O2"; 80 } 81 case OPTIMISE_3: { 82 return "-O3"; 83 } 84 case OPTIMISE_FAST: { 85 return "-Ofast"; 86 } 87 default: { 88 return "-Og"; 89 } 90 } 91 } 92 93 //! @brief Emit code for the plugin-compiler. 94 95 void plugin_driver_emit (FILE_T out) 96 { 97 ADDR_T pop_temp_heap_pointer = A68G (temp_heap_pointer); 98 if (OPTION_OPT_LEVEL (&A68G_JOB) == NO_OPTIMISE) { 99 return; 100 } 101 A68G_OPT (indentation) = 0; 102 A68G_OPT (code_errors) = 0; 103 A68G_OPT (procedures) = 0; 104 A68G_OPT (cse_pointer) = 0; 105 A68G_OPT (unic_pointer) = 0; 106 A68G_OPT (root_idf) = NO_DEC; 107 A68G (global_level) = A68G_MAX_LEX_LEVEL; 108 A68G_GLOBALS = 0; 109 get_global_level (SUB (TOP_NODE (&A68G_JOB))); 110 A68G (max_lex_lvl) = 0; 111 genie_preprocess (TOP_NODE (&A68G_JOB), &A68G (max_lex_lvl), NULL); 112 get_global_level (TOP_NODE (&A68G_JOB)); 113 A68G_SP = A68G (stack_start); 114 A68G (expr_stack_limit) = A68G (stack_end) - A68G (storage_overhead); 115 if (OPTION_COMPILE_CHECK (&A68G_JOB)) { 116 monadics = monadics_check; 117 dyadics = dyadics_check; 118 functions = functions_check; 119 } else { 120 monadics = monadics_nocheck; 121 dyadics = dyadics_nocheck; 122 functions = functions_nocheck; 123 } 124 if (OPTION_OPT_LEVEL (&A68G_JOB) == OPTIMISE_0) { 125 // Allow basic optimisation only. 126 A68G_OPT (OPTION_CODE_LEVEL) = 1; 127 write_prelude (out); 128 gen_basics (TOP_NODE (&A68G_JOB), out); 129 } else { 130 // Allow all optimisations. 131 A68G_OPT (OPTION_CODE_LEVEL) = 9; 132 write_prelude (out); 133 gen_units (TOP_NODE (&A68G_JOB), out); 134 } 135 ABEND (A68G_OPT (indentation) != 0, ERROR_INTERNAL_CONSISTENCY, NO_TEXT); 136 // At the end we discard temporary declarations. 137 A68G (temp_heap_pointer) = pop_temp_heap_pointer; 138 if (OPTION_VERBOSE (&A68G_JOB)) { 139 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "%s: procedures=%d unique-names=%d", A68G (a68g_cmd_name), A68G_OPT (procedures), A68G_OPT (unic_pointer)) >= 0); 140 io_close_tty_line (); 141 WRITE (A68G_STDOUT, A68G (output_line)); 142 } 143 for (int k = 0; k < A68G_OPT (unic_pointer); k++) { 144 a68g_free (UNIC_NAME (k)); 145 } 146 } 147 148 // Pretty printing stuff. 149 150 //! @brief Name formatting 151 152 char *moid_with_name (char *pre, MOID_T * m, char *post) 153 { 154 static char buf[NAME_SIZE]; 155 char *mode = "MODE", *ref = NO_TEXT; 156 if (m != NO_MOID && IS (m, REF_SYMBOL)) { 157 ref = "REF"; 158 m = SUB (m); 159 } 160 if (m == M_INT) { 161 mode = "INT"; 162 } else if (m == M_REAL) { 163 mode = "REAL"; 164 } else if (m == M_BOOL) { 165 mode = "BOOL"; 166 } else if (m == M_CHAR) { 167 mode = "CHAR"; 168 } else if (m == M_BITS) { 169 mode = "BITS"; 170 } else if (m == M_VOID) { 171 mode = "VOID"; 172 } 173 if (ref == NO_TEXT) { 174 a68g_bufprt (buf, NAME_SIZE, "%s%s%s", pre, mode, post); 175 } else { 176 a68g_bufprt (buf, NAME_SIZE, "%sREF_%s%s", pre, mode, post); 177 } 178 return buf; 179 } 180 181 //! @brief Write indented text. 182 183 void indent (FILE_T out, char *str) 184 { 185 int j = A68G_OPT (indentation); 186 if (out == 0) { 187 return; 188 } 189 while (j-- > 0) { 190 WRITE (out, " "); 191 } 192 WRITE (out, str); 193 } 194 195 //! @brief Write unindented text. 196 197 void undent (FILE_T out, char *str) 198 { 199 if (out == 0) { 200 return; 201 } 202 WRITE (out, str); 203 } 204 205 //! @brief Write indent text. 206 207 void indentf (FILE_T out, int ret) 208 { 209 if (out == 0) { 210 return; 211 } 212 if (ret >= 0) { 213 indent (out, A68G (edit_line)); 214 } else { 215 ABEND (A68G_TRUE, ERROR_INTERNAL_CONSISTENCY, error_specification ()); 216 } 217 } 218 219 //! @brief Write unindent text. 220 221 void undentf (FILE_T out, int ret) 222 { 223 if (out == 0) { 224 return; 225 } 226 if (ret >= 0) { 227 WRITE (out, A68G (edit_line)); 228 } else { 229 ABEND (A68G_TRUE, ERROR_INTERNAL_CONSISTENCY, error_specification ()); 230 } 231 } 232 233 // Administration of C declarations . 234 // Pretty printing of C declarations. 235 236 //! @brief Add declaration to a tree. 237 238 DEC_T *add_identifier (DEC_T ** p, int level, char *idf) 239 { 240 char *z = new_temp_string (idf); 241 while (*p != NO_DEC) { 242 int k = strcmp (z, TEXT (*p)); 243 if (k < 0) { 244 p = &LESS (*p); 245 } else if (k > 0) { 246 p = &MORE (*p); 247 } else { 248 ABEND (A68G_TRUE, ERROR_INTERNAL_CONSISTENCY, z); 249 return *p; 250 } 251 } 252 *p = (DEC_T *) get_temp_heap_space (SIZE_ALIGNED (DEC_T)); 253 TEXT (*p) = z; 254 LEVEL (*p) = level; 255 SUB (*p) = LESS (*p) = MORE (*p) = NO_DEC; 256 return *p; 257 } 258 259 //! @brief Add declaration to a tree. 260 261 DEC_T *add_declaration (DEC_T ** p, char *mode, int level, char *idf) 262 { 263 char *z = new_temp_string (mode); 264 while (*p != NO_DEC) { 265 int k = strcmp (z, TEXT (*p)); 266 if (k < 0) { 267 p = &LESS (*p); 268 } else if (k > 0) { 269 p = &MORE (*p); 270 } else { 271 (void) add_identifier (&SUB (*p), level, idf); 272 return *p; 273 } 274 } 275 *p = (DEC_T *) get_temp_heap_space (SIZE_ALIGNED (DEC_T)); 276 TEXT (*p) = z; 277 LEVEL (*p) = -1; 278 SUB (*p) = LESS (*p) = MORE (*p) = NO_DEC; 279 (void) add_identifier (&SUB (*p), level, idf); 280 return *p; 281 } 282 283 //! @brief Print identifiers (following mode). 284 285 void print_identifiers (FILE_T out, DEC_T * p) 286 { 287 if (p != NO_DEC) { 288 print_identifiers (out, LESS (p)); 289 if (A68G_OPT (put_idf_comma)) { 290 WRITE (out, ", "); 291 } else { 292 A68G_OPT (put_idf_comma) = A68G_TRUE; 293 } 294 if (LEVEL (p) > 0) { 295 int k = LEVEL (p); 296 while (k--) { 297 WRITE (out, "*"); 298 } 299 WRITE (out, " "); 300 } 301 WRITE (out, TEXT (p)); 302 print_identifiers (out, MORE (p)); 303 } 304 } 305 306 //! @brief Print declarations. 307 308 void print_declarations (FILE_T out, DEC_T * p) 309 { 310 if (p != NO_DEC) { 311 print_declarations (out, LESS (p)); 312 indent (out, TEXT (p)); 313 WRITE (out, " "); 314 A68G_OPT (put_idf_comma) = A68G_FALSE; 315 print_identifiers (out, SUB (p)); 316 WRITE (out, ";\n"); 317 print_declarations (out, MORE (p)); 318 } 319 } 320 321 // Administration for common functions. 322 // Otherwise we generate many routines that push 0 or 1 or TRUE etc. 323 324 //! @brief Make name. 325 326 char *make_unic_name (char *buf, char *name, char *tag, char *ext) 327 { 328 if (strlen (tag) > 0) { 329 ASSERT (a68g_bufprt (buf, NAME_SIZE, "genie_%s_%s_%s", name, tag, ext) >= 0); 330 } else { 331 ASSERT (a68g_bufprt (buf, NAME_SIZE, "genie_%s_%s", name, ext) >= 0); 332 } 333 ABEND (strlen (buf) >= NAME_SIZE, ERROR_ACTION, NO_TEXT); 334 return buf; 335 } 336 337 //! @brief Look up a name in the list. 338 339 char *signed_in_name (char *name) 340 { 341 for (int k = 0; k < A68G_OPT (unic_pointer); k++) { 342 if (strcmp (UNIC_NAME (k), name) == 0) { 343 return UNIC_NAME (k); 344 } 345 } 346 return NO_TEXT; 347 } 348 349 //! @brief Enter new name in list, if there is space. 350 351 void sign_in_name (char *name, int *action) 352 { 353 if (signed_in_name (name)) { 354 *action = UNIC_EXISTS; 355 } else if (A68G_OPT (unic_pointer) < MAX_UNIC) { 356 UNIC_NAME (A68G_OPT (unic_pointer)) = new_string (name, NO_TEXT); 357 A68G_OPT (unic_pointer)++; 358 *action = UNIC_MAKE_NEW; 359 } else { 360 *action = UNIC_MAKE_ALT; 361 } 362 } 363 364 //! @brief Book identifier to keep track of it for CSE. 365 366 void sign_in (int action, int phase, char *idf, void *info, int number) 367 { 368 if (A68G_OPT (cse_pointer) < MAX_BOOK) { 369 ACTION (&A68G_OPT (cse_book)[A68G_OPT (cse_pointer)]) = action; 370 PHASE (&A68G_OPT (cse_book)[A68G_OPT (cse_pointer)]) = phase; 371 IDF (&A68G_OPT (cse_book)[A68G_OPT (cse_pointer)]) = idf; 372 INFO (&A68G_OPT (cse_book)[A68G_OPT (cse_pointer)]) = info; 373 NUMBER (&A68G_OPT (cse_book)[A68G_OPT (cse_pointer)]) = number; 374 A68G_OPT (cse_pointer)++; 375 } 376 } 377 378 //! @brief Whether identifier is signed_in. 379 380 BOOK_T *signed_in (int action, int phase, const char *idf) 381 { 382 for (int k = 0; k < A68G_OPT (cse_pointer); k++) { 383 if (IDF (&A68G_OPT (cse_book)[k]) == idf && ACTION (&A68G_OPT (cse_book)[k]) == action && PHASE (&A68G_OPT (cse_book)[k]) >= phase) { 384 return &(A68G_OPT (cse_book)[k]); 385 } 386 } 387 return NO_BOOK; 388 } 389 390 //! @brief Make name. 391 392 char *make_name (char *buf, char *name, char *tag, int n) 393 { 394 if (strlen (tag) > 0) { 395 ASSERT (a68g_bufprt (buf, NAME_SIZE, "genie_%s_%s_%d", name, tag, n) >= 0); 396 } else { 397 ASSERT (a68g_bufprt (buf, NAME_SIZE, "genie_%s_%d", name, n) >= 0); 398 } 399 ABEND (strlen (buf) >= NAME_SIZE, ERROR_ACTION, NO_TEXT); 400 return buf; 401 } 402 403 //! @brief Whether two sub-trees are the same Algol 68 construct. 404 405 BOOL_T same_tree (NODE_T * l, NODE_T * r) 406 { 407 if (l == NO_NODE) { 408 return (BOOL_T) (r == NO_NODE); 409 } else if (r == NO_NODE) { 410 return (BOOL_T) (l == NO_NODE); 411 } else if (ATTRIBUTE (l) == ATTRIBUTE (r) && NSYMBOL (l) == NSYMBOL (r)) { 412 return (BOOL_T) (same_tree (SUB (l), SUB (r)) && same_tree (NEXT (l), NEXT (r))); 413 } else { 414 return A68G_FALSE; 415 } 416 } 417 418 // Basic mode check. 419 420 //! @brief Whether stems from certain attribute. 421 422 NODE_T *stems_from (NODE_T * p, int att) 423 { 424 if (IS (p, VOIDING)) { 425 return stems_from (SUB (p), att); 426 } else if (IS (p, UNIT)) { 427 return stems_from (SUB (p), att); 428 } else if (IS (p, TERTIARY)) { 429 return stems_from (SUB (p), att); 430 } else if (IS (p, SECONDARY)) { 431 return stems_from (SUB (p), att); 432 } else if (IS (p, PRIMARY)) { 433 return stems_from (SUB (p), att); 434 } else if (IS (p, att)) { 435 return p; 436 } else { 437 return NO_NODE; 438 } 439 } 440 441 // Auxilliary routines for emitting C code. 442 443 //! @brief Whether frame needs initialisation. 444 445 BOOL_T need_initialise_frame (NODE_T * p) 446 { 447 for (TAG_T *tag = ANONYMOUS (TABLE (p)); tag != NO_TAG; FORWARD (tag)) { 448 if (PRIO (tag) == ROUTINE_TEXT) { 449 return A68G_TRUE; 450 } else if (PRIO (tag) == FORMAT_TEXT) { 451 return A68G_TRUE; 452 } 453 } 454 int count = 0; 455 genie_find_proc_op (p, &count); 456 if (count > 0) { 457 return A68G_TRUE; 458 } else { 459 return A68G_FALSE; 460 } 461 } 462 463 //! @brief Comment source line. 464 465 void comment_tree (NODE_T * p, FILE_T out, int *want_space, int *max_print) 466 { 467 // Take care not to generate nested comments. 468 #define UNDENT(out, p) {\ 469 for (char *q = p; q[0] != NULL_CHAR; q ++) {\ 470 if (q[0] == '*' && q[1] == '/') {\ 471 undent (out, "\\*\\/");\ 472 q ++;\ 473 } else if (q[0] == '/' && q[1] == '*') {\ 474 undent (out, "\\/\\*");\ 475 q ++;\ 476 } else {\ 477 char w[2];\ 478 w[0] = q[0];\ 479 w[1] = NULL_CHAR;\ 480 undent (out, w);\ 481 }\ 482 }} 483 484 for (; p != NO_NODE && (*max_print) >= 0; FORWARD (p)) { 485 if (IS (p, ROW_CHAR_DENOTATION)) { 486 if (*want_space != 0) { 487 UNDENT (out, " "); 488 } 489 UNDENT (out, "\""); 490 UNDENT (out, NSYMBOL (p)); 491 UNDENT (out, "\""); 492 *want_space = 2; 493 } else if (SUB (p) != NO_NODE) { 494 comment_tree (SUB (p), out, want_space, max_print); 495 } else if (NSYMBOL (p)[0] == '(' || NSYMBOL (p)[0] == '[' || NSYMBOL (p)[0] == '{') { 496 if (*want_space == 2) { 497 UNDENT (out, " "); 498 } 499 UNDENT (out, NSYMBOL (p)); 500 *want_space = 0; 501 } else if (NSYMBOL (p)[0] == ')' || NSYMBOL (p)[0] == ']' || NSYMBOL (p)[0] == '}') { 502 UNDENT (out, NSYMBOL (p)); 503 *want_space = 1; 504 } else if (NSYMBOL (p)[0] == ';' || NSYMBOL (p)[0] == ',') { 505 UNDENT (out, NSYMBOL (p)); 506 *want_space = 2; 507 } else if (strlen (NSYMBOL (p)) == 1 && (NSYMBOL (p)[0] == '.' || NSYMBOL (p)[0] == ':')) { 508 UNDENT (out, NSYMBOL (p)); 509 *want_space = 2; 510 } else { 511 if (*want_space != 0) { 512 UNDENT (out, " "); 513 } 514 if ((*max_print) > 0) { 515 UNDENT (out, NSYMBOL (p)); 516 } else if ((*max_print) == 0) { 517 if (*want_space == 0) { 518 UNDENT (out, " "); 519 } 520 UNDENT (out, "..."); 521 } 522 (*max_print)--; 523 if (IS_UPPER (NSYMBOL (p)[0])) { 524 *want_space = 2; 525 } else if (!IS_ALNUM (NSYMBOL (p)[0])) { 526 *want_space = 2; 527 } else { 528 *want_space = 1; 529 } 530 } 531 } 532 #undef UNDENT 533 } 534 535 //! @brief Comment source line. 536 537 void comment_source (NODE_T * p, FILE_T out) 538 { 539 int want_space = 0, max_print = 16, ld = -1; 540 undentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "\n// %s: %d: ", FILENAME (LINE (INFO (p))), LINE_NUMBER (p))); 541 comment_tree (p, out, &want_space, &max_print); 542 tree_listing (out, p, 1, LINE (INFO (p)), &ld, A68G_TRUE); 543 undent (out, "\n"); 544 } 545 546 //! @brief Inline comment source line. 547 548 void inline_comment_source (NODE_T * p, FILE_T out) 549 { 550 int want_space = 0, max_print = 8; 551 undent (out, " // "); 552 comment_tree (p, out, &want_space, &max_print); 553 // undent (out, " */"); 554 } 555 556 //! @brief Write prelude. 557 558 void write_prelude (FILE_T out) 559 { 560 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "// \"%s\" %s\n", FILE_OBJECT_NAME (&A68G_JOB), PACKAGE_STRING)); 561 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "// optimiser_level=%d code_level=%d\n", OPTION_OPT_LEVEL (&A68G_JOB), A68G_OPT (OPTION_CODE_LEVEL))); 562 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "// %s %s\n", __DATE__, __TIME__)); 563 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "\n#include <%s/a68g-config.h>\n", PACKAGE)); 564 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "#include <%s/a68g.h>\n", PACKAGE)); 565 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "#include <%s/a68g-genie.h>\n", PACKAGE)); 566 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "#include <%s/a68g-prelude.h>\n", PACKAGE)); 567 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "#include <%s/a68g-environ.h>\n", PACKAGE)); 568 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "#include <%s/a68g-lib.h>\n", PACKAGE)); 569 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "#include <%s/a68g-optimiser.h>\n", PACKAGE)); 570 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "#include <%s/a68g-frames.h>\n", PACKAGE)); 571 indent (out, "\n#define _NODE_(n) (A68G (node_register)[n])\n"); 572 indent (out, "#define _STATUS_(z) (STATUS (z))\n"); 573 indent (out, "#define _VALUE_(z) (VALUE (z))\n"); 574 } 575 576 //! @brief Write initialisation of frame. 577 578 void init_static_frame (FILE_T out, NODE_T * p) 579 { 580 if (AP_INCREMENT (TABLE (p)) > 0) { 581 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "FRAME_CLEAR (" A68G_LU ");\n", AP_INCREMENT (TABLE (p)))); 582 } 583 if (LEX_LEVEL (p) == A68G (global_level)) { 584 indent (out, "A68G_GLOBALS = A68G_FP;\n"); 585 } 586 if (need_initialise_frame (p)) { 587 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "initialise_frame (_NODE_ (%d));\n", NUMBER (p))); 588 } 589 } 590 591 // COMPILATION OF PARTIAL UNITS. 592 593 void gen_check_init (NODE_T * p, FILE_T out, char *idf) 594 { 595 if (OPTION_COMPILE_CHECK (&A68G_JOB) && folder_mode (MOID (p))) { 596 if (MOID (p) == M_COMPLEX) { 597 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "if (!(INITIALISED (&(*%s)[0]) && INITIALISED (&(*%s)[1]))) {\n", idf, idf)); 598 A68G_OPT (indentation)++; 599 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "diagnostic (A68G_RUNTIME_ERROR, p, ERROR_EMPTY_VALUE_FROM, M_COMPLEX);\n")); 600 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "exit_genie ((p), A68G_RUNTIME_ERROR);\n")); 601 A68G_OPT (indentation)--; 602 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "}\n")); 603 } else { 604 char *M = "M_ERROR"; 605 if (MOID (p) == M_INT) { 606 M = "M_INT"; 607 } else if (MOID (p) == M_REAL) { 608 M = "M_REAL"; 609 } else if (MOID (p) == M_BOOL) { 610 M = "M_BOOL"; 611 } else if (MOID (p) == M_CHAR) { 612 M = "M_CHAR"; 613 } 614 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "if (!INITIALISED(%s)) {\n", idf)); 615 A68G_OPT (indentation)++; 616 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "diagnostic (A68G_RUNTIME_ERROR, p, ERROR_EMPTY_VALUE_FROM, %s);\n", M)); 617 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "exit_genie ((p), A68G_RUNTIME_ERROR);\n")); 618 A68G_OPT (indentation)--; 619 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "}\n")); 620 } 621 } 622 } 623 624 //! @brief Code getting objects from the stack. 625 626 void get_stack (NODE_T * p, FILE_T out, char *dst, char *cast) 627 { 628 if (A68G_OPT (OPTION_CODE_LEVEL) >= 4) { 629 if (LEVEL (GINFO (p)) == A68G (global_level)) { 630 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "GET_GLOBAL (%s, %s, " A68G_LU ");\n", dst, cast, OFFSET (TAX (p)))); 631 } else { 632 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "GET_FRAME (%s, %s, %d, " A68G_LU ");\n", dst, cast, LEVEL (GINFO (p)), OFFSET (TAX (p)))); 633 } 634 } else { 635 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "GET_FRAME (%s, %s, %d, " A68G_LU ");\n", dst, cast, LEVEL (GINFO (p)), OFFSET (TAX (p)))); 636 } 637 } 638 639 //! @brief Code function prelude. 640 641 void write_fun_prelude (NODE_T * p, FILE_T out, char *fn) 642 { 643 (void) p; 644 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "\nPROP_T %s (NODE_T *p) {\n", fn)); 645 A68G_OPT (indentation)++; 646 indent (out, "PROP_T self;\n"); 647 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "UNIT (&self) = %s;\n", fn)); 648 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "SOURCE (&self) = _NODE_ (%d);\n", NUMBER (p))); 649 A68G_OPT (cse_pointer) = 0; 650 } 651 652 //! @brief Code function postlude. 653 654 void write_fun_postlude (NODE_T * p, FILE_T out, char *fn) 655 { 656 (void) fn; 657 (void) p; 658 indent (out, "return (self);\n"); 659 A68G_OPT (indentation)--; 660 A68G_OPT (procedures)++; 661 indent (out, "}\n"); 662 A68G_OPT (cse_pointer) = 0; 663 } 664 665 //! @brief Code internal a68g mode. 666 667 char *internal_mode (const MOID_T * m) 668 { 669 if (m == M_INT) { 670 return "M_INT"; 671 } else if (m == M_REAL) { 672 return "M_REAL"; 673 } else if (m == M_BOOL) { 674 return "M_BOOL"; 675 } else if (m == M_CHAR) { 676 return "M_CHAR"; 677 } else if (m == M_BITS) { 678 return "M_BITS"; 679 } else { 680 return "M_ERROR"; 681 } 682 } 683 684 //! @brief Compile denotation. 685 686 char *compile_denotation (NODE_T * p, FILE_T out) 687 { 688 if (primitive_mode (MOID (p))) { 689 static char fn[NAME_SIZE], N[NAME_SIZE]; 690 int action = UNIC_MAKE_ALT; 691 comment_source (p, out); 692 fn[0] = '\0'; 693 if (MOID (p) == M_INT) { 694 char *end; 695 UNSIGNED_T z = (UNSIGNED_T) a68g_strtoi (NSYMBOL (p), &end, 10); 696 ASSERT (a68g_bufprt (N, NAME_SIZE, A68G_LX "_", z) >= 0); 697 (void) make_unic_name (fn, moid_with_name ("", MOID (p), "_denotation"), "", N); 698 } else if (MOID (p) == M_REAL) { 699 A68G_SP = 0; 700 PUSH_UNION (p, M_REAL); 701 push_unit (p); 702 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_REAL))); 703 PUSH_VALUE (p, A68G_REAL_WIDTH + A68G_EXP_WIDTH + 5, A68G_INT); 704 PUSH_VALUE (p, A68G_REAL_WIDTH, A68G_INT); 705 PUSH_VALUE (p, A68G_EXP_WIDTH + 1, A68G_INT); 706 PUSH_VALUE (p, 3, A68G_INT); 707 char *V = real (p); 708 char W[NAME_SIZE]; 709 for (int k = 0; V[0] != '\0'; V++) { 710 if (IS_ALNUM (V[0])) { 711 W[k++] = TO_LOWER (V[0]); 712 W[k] = '\0'; 713 } 714 if (V[0] == '.' || V[0] == '-') { 715 W[k++] = '_'; 716 W[k] = '\0'; 717 } 718 } 719 (void) make_unic_name (fn, moid_with_name ("", MOID (p), "_denotation"), "", W); 720 } else if (MOID (p) == M_BOOL) { 721 (void) make_unic_name (fn, moid_with_name ("", MOID (p), "_denotation"), "", NSYMBOL (SUB (p))); 722 } else if (MOID (p) == M_CHAR) { 723 ASSERT (a68g_bufprt (N, NAME_SIZE, "%02x_", NSYMBOL (SUB (p))[0]) >= 0); 724 (void) make_unic_name (fn, moid_with_name ("", MOID (p), "_denotation"), "", N); 725 } 726 if (fn[0] != '\0') { 727 sign_in_name (fn, &action); 728 if (action == UNIC_EXISTS) { 729 return fn; 730 } 731 } 732 if (action == UNIC_MAKE_NEW || action == UNIC_MAKE_ALT) { 733 if (action == UNIC_MAKE_ALT) { 734 (void) make_name (fn, moid_with_name ("", MOID (p), "_denotation_alt"), "", NUMBER (p)); 735 } 736 write_fun_prelude (p, out, fn); 737 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "PUSH_VALUE (p, ")); 738 inline_unit (p, out, L_YIELD); 739 undentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, ", %s);\n", inline_mode (MOID (p)))); 740 write_fun_postlude (p, out, fn); 741 } 742 return fn; 743 } else { 744 return NO_TEXT; 745 } 746 } 747 748 char *compile_cast (NODE_T * p, FILE_T out) 749 { 750 if (folder_mode (MOID (p)) && basic_unit (p)) { 751 static char fn[NAME_SIZE]; 752 comment_source (p, out); 753 (void) make_name (fn, moid_with_name ("", MOID (p), "_cast"), "", NUMBER (p)); 754 A68G_OPT (root_idf) = NO_DEC; 755 inline_unit (NEXT_SUB (p), out, L_DECLARE); 756 print_declarations (out, A68G_OPT (root_idf)); 757 inline_unit (NEXT_SUB (p), out, L_EXECUTE); 758 gen_push (NEXT_SUB (p), out); 759 return fn; 760 } else { 761 return NO_TEXT; 762 } 763 } 764 765 //! @brief Compile identifier. 766 767 char *compile_identifier (NODE_T * p, FILE_T out) 768 { 769 if (folder_mode (MOID (p))) { 770 static char fn[NAME_SIZE]; 771 int action = UNIC_MAKE_ALT; 772 char N[NAME_SIZE]; 773 // Some identifiers in standenv cannot be pushed. 774 // Examples are cputime, or clock that are procedures in disguise. 775 if (A68G_STANDENV_PROC (TAX (p))) { 776 BOOL_T ok = A68G_FALSE; 777 for (int k = 0; PROCEDURE (&constants[k]) != NO_GPROC; k++) { 778 if (PROCEDURE (TAX (p)) == PROCEDURE (&constants[k])) { 779 ok = A68G_TRUE; 780 } 781 } 782 if (!ok) { 783 return NO_TEXT; 784 } 785 } 786 // Push the identifier. 787 ASSERT (a68g_bufprt (N, NAME_SIZE, "%d_%d_" A68G_LU, NUM (TABLE (TAX (p))), LEVEL (GINFO (p)), OFFSET (TAX (p))) >= 0); 788 comment_source (p, out); 789 fn[0] = '\0'; 790 (void) make_unic_name (fn, moid_with_name ("", MOID (p), "_identifier"), "", N); 791 sign_in_name (fn, &action); 792 if (action == UNIC_EXISTS) { 793 return fn; 794 } 795 if (action == UNIC_MAKE_NEW || action == UNIC_MAKE_ALT) { 796 if (action == UNIC_MAKE_ALT) { 797 (void) make_name (fn, moid_with_name ("", MOID (p), "_identifier_alt"), "", NUMBER (p)); 798 } 799 write_fun_prelude (p, out, fn); 800 A68G_OPT (root_idf) = NO_DEC; 801 inline_unit (p, out, L_DECLARE); 802 print_declarations (out, A68G_OPT (root_idf)); 803 inline_unit (p, out, L_EXECUTE); 804 gen_push (p, out); 805 write_fun_postlude (p, out, fn); 806 } 807 return fn; 808 } else { 809 return NO_TEXT; 810 } 811 } 812 813 //! @brief Compile dereference identifier. 814 815 char *compile_dereference_identifier (NODE_T * p, FILE_T out) 816 { 817 if (folder_mode (MOID (p))) { 818 static char fn[NAME_SIZE]; 819 int action = UNIC_MAKE_ALT; 820 char N[NAME_SIZE]; 821 NODE_T *q = SUB (p); 822 ASSERT (a68g_bufprt (N, NAME_SIZE, "%d_%d_" A68G_LU, NUM (TABLE (TAX (q))), LEVEL (GINFO (q)), OFFSET (TAX (q))) >= 0); 823 comment_source (p, out); 824 fn[0] = '\0'; 825 (void) make_unic_name (fn, moid_with_name ("deref_REF_", MOID (p), "_identifier"), "", N); 826 sign_in_name (fn, &action); 827 if (action == UNIC_EXISTS) { 828 return fn; 829 } 830 if (action == UNIC_MAKE_NEW || action == UNIC_MAKE_ALT) { 831 if (action == UNIC_MAKE_ALT) { 832 (void) make_name (fn, moid_with_name ("deref_REF_", MOID (p), "_identifier_alt"), "", NUMBER (p)); 833 } 834 write_fun_prelude (p, out, fn); 835 A68G_OPT (root_idf) = NO_DEC; 836 inline_unit (p, out, L_DECLARE); 837 print_declarations (out, A68G_OPT (root_idf)); 838 inline_unit (p, out, L_EXECUTE); 839 gen_push (p, out); 840 write_fun_postlude (p, out, fn); 841 } 842 return fn; 843 } else { 844 return NO_TEXT; 845 } 846 } 847 848 //! @brief Compile formula. 849 850 char *compile_formula (NODE_T * p, FILE_T out) 851 { 852 if (folder_mode (MOID (p)) && basic_unit (p)) { 853 static char fn[NAME_SIZE]; 854 comment_source (p, out); 855 (void) make_name (fn, moid_with_name ("", MOID (p), "_formula"), "", NUMBER (p)); 856 write_fun_prelude (p, out, fn); 857 if (OPTION_COMPILE_CHECK (&A68G_JOB) && !constant_unit (p)) { 858 if (MOID (p) == M_REAL || MOID (p) == M_COMPLEX) { 859 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "A68G_REAL * _st_ = (A68G_REAL *) STACK_TOP;\n")); 860 } 861 } 862 A68G_OPT (root_idf) = NO_DEC; 863 inline_unit (p, out, L_DECLARE); 864 print_declarations (out, A68G_OPT (root_idf)); 865 if (OPTION_COMPILE_CHECK (&A68G_JOB) && !constant_unit (p)) { 866 if (folder_mode (MOID (p))) { 867 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "errno = 0;\n")); 868 } 869 } 870 inline_unit (p, out, L_EXECUTE); 871 gen_push (p, out); 872 if (OPTION_COMPILE_CHECK (&A68G_JOB) && !constant_unit (p)) { 873 if (MOID (p) == M_INT) { 874 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "MATH_RTE (p, errno != 0, M_INT, NO_TEXT);\n")); 875 } 876 if (MOID (p) == M_REAL) { 877 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "MATH_RTE (p, errno != 0, M_REAL, NO_TEXT);\n")); 878 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "CHECK_REAL (p, _VALUE_ (_st_));\n")); 879 } 880 if (MOID (p) == M_BITS) { 881 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "MATH_RTE (p, errno != 0, M_BITS, NO_TEXT);\n")); 882 } 883 if (MOID (p) == M_COMPLEX) { 884 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "MATH_RTE (p, errno != 0, M_COMPLEX, NO_TEXT);\n")); 885 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "CHECK_REAL (p, _VALUE_ (&(_st_[0])));\n")); 886 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "CHECK_REAL (p, _VALUE_ (&(_st_[1])));\n")); 887 } 888 } 889 write_fun_postlude (p, out, fn); 890 return fn; 891 } else { 892 return NO_TEXT; 893 } 894 } 895 896 //! @brief Compile call. 897 898 char *compile_call (NODE_T * p, FILE_T out) 899 { 900 NODE_T *proc = SUB (p); 901 NODE_T *args = NEXT (proc); 902 NODE_T *idf = stems_from (proc, IDENTIFIER); 903 if (idf == NO_NODE) { 904 return NO_TEXT; 905 } else if (!(SUB_MOID (proc) == M_VOID || basic_mode (SUB_MOID (proc)))) { 906 return NO_TEXT; 907 } else if (DIM (MOID (proc)) == 0) { 908 return NO_TEXT; 909 } else if (A68G_STANDENV_PROC (TAX (idf))) { 910 if (basic_call (p)) { 911 static char fun[NAME_SIZE]; 912 comment_source (p, out); 913 (void) make_name (fun, moid_with_name ("", SUB_MOID (proc), "_call"), "", NUMBER (p)); 914 write_fun_prelude (p, out, fun); 915 A68G_OPT (root_idf) = NO_DEC; 916 inline_unit (p, out, L_DECLARE); 917 print_declarations (out, A68G_OPT (root_idf)); 918 inline_unit (p, out, L_EXECUTE); 919 gen_push (p, out); 920 write_fun_postlude (p, out, fun); 921 return fun; 922 } else { 923 return NO_TEXT; 924 } 925 } else if (!(CODEX (TAX (idf)) & PROC_DECLARATION_MASK)) { 926 return NO_TEXT; 927 } else if (DIM (PARTIAL_PROC (GINFO (proc))) != 0) { 928 return NO_TEXT; 929 } else if (!basic_argument (args)) { 930 return NO_TEXT; 931 } else { 932 static char fn[NAME_SIZE]; 933 char fun[NAME_SIZE], pop[NAME_SIZE]; 934 // Declare. 935 (void) make_name (fun, FUN, "", NUMBER (proc)); 936 (void) make_name (pop, PUP, "", NUMBER (p)); 937 comment_source (p, out); 938 (void) make_name (fn, moid_with_name ("", SUB_MOID (proc), "_call"), "", NUMBER (p)); 939 write_fun_prelude (p, out, fn); 940 // Compute arguments. 941 size_t size = 0; 942 A68G_OPT (root_idf) = NO_DEC; 943 inline_arguments (args, out, L_DECLARE, &size); 944 (void) add_declaration (&A68G_OPT (root_idf), "ADDR_T", 0, pop); 945 (void) add_declaration (&A68G_OPT (root_idf), "A68G_PROCEDURE", 1, fun); 946 (void) add_declaration (&A68G_OPT (root_idf), "NODE_T", 1, "body"); 947 print_declarations (out, A68G_OPT (root_idf)); 948 // Initialise. 949 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "%s = A68G_SP;\n", pop)); 950 inline_arguments (args, out, L_INITIALISE, &size); 951 get_stack (idf, out, fun, "A68G_PROCEDURE"); 952 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "body = SUB (NODE (&BODY (%s)));\n", fun)); 953 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "OPEN_PROC_FRAME (body, ENVIRON (%s));\n", fun)); 954 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "INIT_STATIC_FRAME (body);\n")); 955 size = 0; 956 inline_arguments (args, out, L_EXECUTE, &size); 957 size = 0; 958 inline_arguments (args, out, L_YIELD, &size); 959 // Execute procedure. 960 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "A68G_SP = %s;\n", pop)); 961 indent (out, "GENIE_UNIT_TRACE (NEXT_NEXT_NEXT (body));\n"); 962 indent (out, "if (A68G_FP == A68G_MON (finish_frame_pointer)) {\n"); 963 A68G_OPT (indentation)++; 964 indentf (out, a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "change_masks (TOP_NODE (&A68G_JOB), BREAKPOINT_INTERRUPT_MASK, A68G_TRUE);\n")); 965 A68G_OPT (indentation)--; 966 indent (out, "}\n"); 967 indent (out, "CLOSE_FRAME;\n"); 968 write_fun_postlude (p, out, fn); 969 return fn; 970 } 971 } 972
© 2001-2026 J.M. van der Veer
jmvdveer@algol68genie.nl