Changeset 2789 in kBuild for trunk/src/kmk/kmk_cc_exec.c
- Timestamp:
- Sep 12, 2015 11:44:09 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/kmk_cc_exec.c
r2788 r2789 42 42 #include <stdarg.h> 43 43 #include <assert.h> 44 #include "k/kDefs.h" 45 #include "k/kTypes.h" 44 46 45 47 … … 117 119 118 120 121 /** @def KMK_CC_IS_SPACE_CH 122 * Checks if it's a space char. */ 123 #define KMK_CC_IS_SPACE_CH(a_ch) isspace((unsigned char)(a_ch)) 124 125 126 /** @defgroup grp_kmk_cc_evalprog Makefile Evaluation 127 * @{ 128 */ 129 /** @name KMK_CC_EVAL_QUALIFIER_XXX - Variable qualifiers. 130 * @{ */ 131 #define KMK_CC_EVAL_QUALIFIER_LOCAL 1 132 #define KMK_CC_EVAL_QUALIFIER_EXPORT 2 133 #define KMK_CC_EVAL_QUALIFIER_OVERRIDE 4 134 #define KMK_CC_EVAL_QUALIFIER_PRIVATE 8 135 /** @} */ 136 137 /** Eval: Max nesting depth of makefile conditionals. 138 * Affects stack usage in kmk_cc_eval_compile_worker. */ 139 #define KMK_CC_EVAL_MAX_IF_DEPTH 32 140 /** Eval: Maximum number of escaped end of line sequences to track. 141 * Affects stack usage in kmk_cc_eval_compile_worker, but not the actual 142 * number of consequtive escaped newlines in the input file/variable. */ 143 #define KMK_CC_EVAL_MAX_ESC_EOLS 2 144 145 /** Minimum keyword length. */ 146 #define KMK_CC_EVAL_KEYWORD_MIN 2 147 /** Maximum keyword length. */ 148 #define KMK_CC_EVAL_KEYWORD_MAX 16 149 150 /** @name KMK_CC_EVAL_CH_XXX - flags found in g_abEvalCcChars. 151 * @{ */ 152 /** Normal character, nothing special. */ 153 #define KMK_CC_EVAL_CH_NORMAL UINT8_C(0) 154 /** Blank character. */ 155 #define KMK_CC_EVAL_CH_BLANK UINT8_C(1) 156 #define KMK_CC_EVAL_IS_BLANK(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_BLANK) 157 /** Space character. */ 158 #define KMK_CC_EVAL_CH_SPACE UINT8_C(2) 159 #define KMK_CC_EVAL_IS_SPACE(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_SPACE) 160 /** Space character or potential EOL escape backslash. */ 161 #define KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH UINT8_C(4) 162 #define KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH) 163 /** Possible EOL character. */ 164 #define KMK_CC_EVAL_CH_EOL_CANDIDATE UINT8_C(8) 165 #define KMK_CC_EVAL_IS_EOL_CANDIDATE(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_EOL_CANDIDATE) 166 /** First character in a keyword. */ 167 #define KMK_CC_EVAL_CH_1ST_IN_KEYWORD UINT8_C(16) 168 #define KMK_CC_EVAL_IS_1ST_IN_KEYWORD(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_1ST_IN_KEYWORD) 169 /** Second character in a keyword. */ 170 #define KMK_CC_EVAL_CH_2ND_IN_KEYWORD UINT8_C(32) 171 #define KMK_CC_EVAL_IS_2ND_IN_KEYWORD(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_2ND_IN_KEYWORD) 172 /** First character in a variable qualifier keyword or 'define'. */ 173 #define KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD UINT8_C(64) 174 #define KMK_CC_EVAL_IS_1ST_IN_VARIABLE_KEYWORD(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD) 175 /** Assignment punctuation character. */ 176 #define KMK_CC_EVAL_CH_ASSIGNMENT UINT8_C(128) 177 #define KMK_CC_EVAL_IS_ASSIGNMENT(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_ASSIGNMENT) 178 /** @} */ 179 180 /** Sets a bitmap entry. 181 * @param a_abBitmap Typically g_abEvalCcChars. 182 * @param a_ch The character to set. 183 * @param a_uVal The value to OR in. */ 184 #define KMK_CC_EVAL_BM_OR(g_abBitmap, a_ch, a_uVal) do { (g_abBitmap)[(unsigned char)(a_ch)] |= (a_uVal); } while (0) 185 186 /** Gets a bitmap entry. 187 * @returns The value corresponding to @a a_ch. 188 * @param a_abBitmap Typically g_abEvalCcChars. 189 * @param a_ch The character to set. */ 190 #define KMK_CC_EVAL_BM_GET(g_abBitmap, a_ch) ( (g_abBitmap)[(unsigned char)(a_ch)] ) 191 192 /** @} */ 193 194 119 195 /********************************************************************************************************************************* 120 196 * Structures and Typedefs * … … 139 215 140 216 141 /** @ nameString Expansion217 /** @defgroup grp_kmk_cc_exp String Expansion 142 218 * @{*/ 143 219 … … 406 482 407 483 408 /** @ name Makefile Evaluation484 /** @addtogroup grp_kmk_cc_evalprog 409 485 * @{ */ 410 486 … … 487 563 /** Adds more commands to the current recipe - KMKCCEVALRECIPECOMMANDS. */ 488 564 kKmkCcEvalInstr_recipe_commands, 489 /** Adds more commands to the current recipe - KMKCCEVALRECIPECOMMANDS. */490 kKmkCcEvalInstr_recipe_vari,491 565 /** Special instruction for indicating the end of the recipe commands - KMKCCEVALCORE. */ 492 566 kKmkCcEvalInstr_recipe_end, … … 602 676 PKMKCCEVALCORE pNextFalse; 603 677 /** Pointer to the previous conditional for 'else if*' directives. 604 * This is to assist the compilation process. */ 605 PKMKCCEVALCORE pPrevCond; 678 * This is only to assist the compilation process. */ 679 struct kmk_cc_eval_if_core *pPrevCond; 680 /** Pointer to the jump out of the true block, if followed by 'else'. 681 * This is only to assist the compilation process. */ 682 PKMKCCEVALJUMP pTrueEndJump; 606 683 } KMKCCEVALIFCORE; 607 684 typedef KMKCCEVALIFCORE *PKMKCCEVALIFCORE; … … 633 710 KMKCCEXPSUBPROG NameSubProg; 634 711 } KMKCCEVALIFDEFDYNAMIC; 635 KMK_CC_STATIC_ASSERT(sizeof(KMKCCEVALIFDEFDYNAMIC) == 48 || sizeof(void *) != 8);636 712 typedef KMKCCEVALIFDEFDYNAMIC *PKMKCCEVALIFDEFDYNAMIC; 637 713 … … 752 828 * counts. Expressions will be expanded and split on space. 753 829 * 754 * The KMKCCEXPSUBPROGORPLAIN::bUser member is used to indicate secondary 755 * expansion for a plain text entry. 830 * The KMKCCEXPSUBPROGORPLAIN::bUser member one of KMKCCEVALRECIPE_FD_XXX. 756 831 * 757 832 * @todo Plain text file name could be replaced by file string cache entries. */ … … 762 837 * files. */ 763 838 #define KMKCCEVALRECIPE_SIZE(a_cFilesAndDeps) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALRECIPE, aFilesAndDeps, a_cFilesAndDeps) 839 /** @name KMKCCEVALRECIPE_FD_XXX - Values for KMKCCEVALRECIPE::aFilesAndDeps[x].bUser 840 * @{ */ 841 #define KMKCCEVALRECIPE_FD_NORMAL 0 842 #define KMKCCEVALRECIPE_FD_SEC_EXP 1 843 #define KMKCCEVALRECIPE_FD_SPECIAL_POSIX 2 844 #define KMKCCEVALRECIPE_FD_SPECIAL_SECONDEXPANSION 3 845 #define KMKCCEVALRECIPE_FD_SPECIAL_ONESHELL 4 846 /** @} */ 847 764 848 765 849 /** … … 815 899 /** List of blocks for this program (LIFO). */ 816 900 PKMKCCBLOCK pBlockTail; 817 901 /** The name of the file containing this program. */ 902 const char *pszFilename; 903 /** The name of the variable containing this program, if applicable. */ 904 const char *pszVarName; 905 #ifdef KMK_CC_STRICT 906 /** The hash of the input string. Used to check that we get all the change 907 * notifications we require. */ 908 uint32_t uInputHash; 909 #endif 910 /** Reference count. */ 911 uint32_t volatile cRefs; 818 912 } KMKCCEVALPROG; 913 typedef KMKCCEVALPROG *PKMKCCEVALPROG; 819 914 820 915 /** @} */ … … 826 921 static uint32_t g_cVarForExpandCompilations = 0; 827 922 static uint32_t g_cVarForExpandExecs = 0; 923 static uint32_t g_cVarForEvalCompilations = 0; 924 static uint32_t g_cVarForEvalExecs = 0; 925 static uint32_t g_cFileForEvalCompilations = 0; 926 static uint32_t g_cFileForEvalExecs = 0; 828 927 #ifdef KMK_CC_WITH_STATS 829 928 static uint32_t g_cBlockAllocated = 0; 830 929 static uint32_t g_cbAllocated = 0; 930 831 931 static uint32_t g_cBlocksAllocatedExpProgs = 0; 832 932 static uint32_t g_cbAllocatedExpProgs = 0; … … 835 935 static uint32_t g_cMultiBlockExpProgs = 0; 836 936 static uint32_t g_cbUnusedMemExpProgs = 0; 937 938 static uint32_t g_cBlocksAllocatedEvalProgs = 0; 939 static uint32_t g_cbAllocatedEvalProgs = 0; 940 static uint32_t g_cSingleBlockEvalProgs = 0; 941 static uint32_t g_cTwoBlockEvalProgs = 0; 942 static uint32_t g_cMultiBlockEvalProgs = 0; 943 static uint32_t g_cbUnusedMemEvalProgs = 0; 944 837 945 #endif 946 947 /** Bitmap taking 'unsigned char' index. 948 * ASSUMES unsigned char is 8-bits. */ 949 static uint8_t g_abEvalCcChars[256]; 950 951 /** 952 * Makefile evaluation keywords. 953 */ 954 static const char * const g_apszEvalKeywords[] = 955 { 956 "define", 957 "export", 958 "else", 959 "endef", 960 "endif", 961 "ifdef", 962 "ifndef", 963 "ifeq", 964 "ifneq", 965 "if1of", 966 "ifn1of", 967 "if", 968 "include", 969 "includedep", 970 "includedep-queue", 971 "includedep-flush", 972 "local", 973 "override", 974 "private", 975 "sinclude", 976 "unexport", 977 "undefine", 978 "vpath", 979 "-include", 980 }; 838 981 839 982 … … 850 993 void kmk_cc_init(void) 851 994 { 995 unsigned i; 996 997 /* 998 * Initialize the bitmap. 999 */ 1000 memset(g_abEvalCcChars, 0, sizeof(g_abEvalCcChars)); 1001 1002 /* blank chars */ 1003 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ' ', KMK_CC_EVAL_CH_BLANK); 1004 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\t', KMK_CC_EVAL_CH_BLANK); 1005 1006 /* space chars and zero terminator. */ 1007 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ' ', KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH); 1008 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\t', KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH); 1009 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\n', KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_EOL_CANDIDATE); 1010 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\v', KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH); 1011 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\f', KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH); 1012 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\r', KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_EOL_CANDIDATE); 1013 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH); 1014 1015 /* keywords */ 1016 for (i = 0; i < K_ELEMENTS(g_apszEvalKeywords); i++) 1017 { 1018 size_t cch = strlen(g_apszEvalKeywords[i]); 1019 KMK_CC_ASSERT(cch >= KMK_CC_EVAL_KEYWORD_MIN); 1020 KMK_CC_ASSERT(cch <= KMK_CC_EVAL_KEYWORD_MAX); 1021 1022 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, g_apszEvalKeywords[i][0], KMK_CC_EVAL_CH_1ST_IN_KEYWORD); 1023 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, g_apszEvalKeywords[i][1], KMK_CC_EVAL_CH_2ND_IN_KEYWORD); 1024 } 1025 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'd', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* define */ 1026 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'e', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* export (, endef) */ 1027 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'l', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* local */ 1028 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'o', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* override */ 1029 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'p', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* private */ 1030 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'u', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* undefine */ 1031 1032 /* Assignment punctuation. */ 1033 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '=', KMK_CC_EVAL_CH_ASSIGNMENT); 1034 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ':', KMK_CC_EVAL_CH_ASSIGNMENT); 1035 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '<', KMK_CC_EVAL_CH_ASSIGNMENT); 1036 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '?', KMK_CC_EVAL_CH_ASSIGNMENT); 1037 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '+', KMK_CC_EVAL_CH_ASSIGNMENT); 852 1038 } 853 1039 … … 858 1044 void kmk_cc_print_stats(void) 859 1045 { 1046 #ifdef KMK_CC_WITH_STATS 1047 uint32_t const cEvalCompilations = g_cFileForEvalCompilations + g_cVarForEvalCompilations; 1048 #endif 1049 860 1050 puts(_("\n# The kmk 'compiler' and kmk 'program executor':\n")); 861 1051 … … 880 1070 g_cbUnusedMemExpProgs, (uint32_t)((uint64_t)g_cbUnusedMemExpProgs * 100 / g_cbAllocatedExpProgs), 881 1071 g_cbUnusedMemExpProgs / g_cBlocksAllocatedExpProgs); 882 1072 puts(""); 1073 #endif 1074 printf(_("# Variables compiled for string eval: %6u\n"), g_cVarForEvalCompilations); 1075 printf(_("# Variables string eval runs: %6u\n"), g_cVarForEvalExecs); 1076 printf(_("# String evals runs per compile: %6u\n"), g_cVarForEvalExecs / g_cVarForEvalCompilations); 1077 printf(_("# Files compiled: %6u\n"), g_cFileForEvalCompilations); 1078 printf(_("# Files runs: %6u\n"), g_cFileForEvalExecs); 1079 printf(_("# Files eval runs per compile: %6u\n"), g_cFileForEvalExecs / g_cFileForEvalCompilations); 1080 #ifdef KMK_CC_WITH_STATS 1081 printf(_("# Single alloc block eval progs: %6u (%u%%)\n" 1082 "# Two alloc block eval progs: %6u (%u%%)\n" 1083 "# Three or more alloc block eval progs: %6u (%u%%)\n" 1084 ), 1085 g_cSingleBlockEvalProgs, (uint32_t)((uint64_t)g_cSingleBlockEvalProgs * 100 / cEvalCompilations), 1086 g_cTwoBlockEvalProgs, (uint32_t)((uint64_t)g_cTwoBlockEvalProgs * 100 / cEvalCompilations), 1087 g_cMultiBlockEvalProgs, (uint32_t)((uint64_t)g_cMultiBlockEvalProgs * 100 / cEvalCompilations)); 1088 printf(_("# Total amount of memory for eval progs: %8u bytes\n" 1089 "# in: %6u blocks\n" 1090 "# avg block size: %6u bytes\n" 1091 "# unused memory: %8u bytes (%u%%)\n" 1092 "# avg unused memory per block: %6u bytes\n" 1093 "\n"), 1094 g_cbAllocatedEvalProgs, g_cBlocksAllocatedEvalProgs, g_cbAllocatedEvalProgs / g_cBlocksAllocatedEvalProgs, 1095 g_cbUnusedMemEvalProgs, (uint32_t)((uint64_t)g_cbUnusedMemEvalProgs * 100 / g_cbAllocatedEvalProgs), 1096 g_cbUnusedMemEvalProgs / g_cBlocksAllocatedEvalProgs); 1097 puts(""); 883 1098 printf(_("# Total amount of block mem allocated: %8u bytes\n"), g_cbAllocated); 884 1099 printf(_("# Total number of block allocated: %8u\n"), g_cBlockAllocated); … … 978 1193 979 1194 KMK_CC_ASSERT_ALIGNED(cbFirst, sizeof(void *)); 1195 KMK_CC_ASSERT(cbFirst <= 128); 980 1196 981 1197 /* 982 1198 * Turn the hint into a block size. 983 1199 */ 1200 cbHint += cbFirst; 984 1201 if (cbHint <= 512) 985 1202 { 986 1203 if (cbHint <= 256) 987 cbBlock = 128; 1204 { 1205 if (cbFirst <= 64) 1206 cbBlock = 128; 1207 else 1208 cbBlock = 256; 1209 } 988 1210 else 989 1211 cbBlock = 256; … … 1210 1432 1211 1433 /** 1434 * Grows the allocation with another block, makefile evaluation program case. 1435 * 1436 * @returns Pointer to a makefile evaluation instruction core. 1437 * @param ppBlockTail Pointer to the allocator tail pointer. 1438 * @param cb The number of bytes to allocate. 1439 */ 1440 static PKMKCCEVALCORE kmk_cc_block_alloc_eval_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb) 1441 { 1442 PKMKCCBLOCK pOldBlock = *ppBlockTail; 1443 PKMKCCBLOCK pNewBlock; 1444 PKMKCCEVALCORE pRet; 1445 PKMKCCEVALJUMP pJump; 1446 1447 /* Figure the block size. */ 1448 uint32_t cbBlock = !pOldBlock->pNext ? 128 : pOldBlock->cbBlock; 1449 while (cbBlock - sizeof(KMKCCEVALJUMP) - sizeof(*pNewBlock) < cb) 1450 cbBlock *= 2; 1451 1452 /* Allocate and initialize the block it with the new instruction already accounted for. */ 1453 pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock); 1454 pNewBlock->cbBlock = cbBlock; 1455 pNewBlock->offNext = sizeof(*pNewBlock) + cb; 1456 pNewBlock->pNext = pOldBlock; 1457 *ppBlockTail = pNewBlock; 1458 1459 #ifdef KMK_CC_WITH_STATS 1460 g_cBlockAllocated++; 1461 g_cbAllocated += cbBlock; 1462 #endif 1463 1464 pRet = (PKMKCCEVALCORE)(pNewBlock + 1); 1465 1466 /* Emit jump. */ 1467 pJump = (PKMKCCEVALJUMP)((char *)pOldBlock + pOldBlock->offNext); 1468 pJump->Core.enmOpCode = kKmkCcEvalInstr_jump; 1469 pJump->pNext = pRet; 1470 pOldBlock->offNext += sizeof(*pJump); 1471 KMK_CC_ASSERT(pOldBlock->offNext <= pOldBlock->cbBlock); 1472 1473 return pRet; 1474 } 1475 1476 1477 /** 1478 * Allocates a makefile evaluation instruction of size @a cb. 1479 * 1480 * @returns Pointer to a makefile evaluation instruction core. 1481 * @param ppBlockTail Pointer to the allocator tail pointer. 1482 * @param cb The number of bytes to allocate. 1483 */ 1484 static PKMKCCEVALCORE kmk_cc_block_alloc_eval(PKMKCCBLOCK *ppBlockTail, uint32_t cb) 1485 { 1486 PKMKCCBLOCK pBlockTail = *ppBlockTail; 1487 uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext; 1488 1489 KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEVALJUMP)); 1490 KMK_CC_ASSERT( (cb & (sizeof(void *) - 1)) == 0 ); 1491 1492 if (cbLeft >= cb + sizeof(KMKCCEVALJUMP)) 1493 { 1494 PKMKCCEVALCORE pRet = (PKMKCCEVALCORE)((char *)pBlockTail + pBlockTail->offNext); 1495 pBlockTail->offNext += cb; 1496 return pRet; 1497 } 1498 return kmk_cc_block_alloc_eval_grow(ppBlockTail, cb); 1499 } 1500 1501 1502 /** 1212 1503 * Frees all memory used by an allocator. 1213 1504 * … … 1224 1515 } 1225 1516 1226 /* 1517 1518 /* 1227 1519 * 1228 1520 * The string expansion compiler. … … 2439 2731 * 2440 2732 */ 2733 2734 static size_t kmk_cc_eval_detect_eol_style(char *pchFirst, char *pchSecond, const char *pszContent, size_t cchContent) 2735 { 2736 /* Look for LF first. */ 2737 const char *pszTmp = (const char *)memchr(pszContent, '\n', cchContent); 2738 if (pszTmp) 2739 { 2740 /* CRLF? */ 2741 if (pszTmp != pszContent && pszTmp[-1] == '\r') 2742 { 2743 *pchFirst = '\r'; 2744 *pchSecond = '\n'; 2745 return 2; 2746 } 2747 2748 /* No, LF or LFCR. (pszContent is zero terminated, so no bounds checking necessary.) */ 2749 *pchFirst = '\n'; 2750 if (pszTmp[1] != '\r') 2751 { 2752 *pchSecond = 0; 2753 return 1; 2754 } 2755 *pchSecond = '\r'; 2756 return 2; 2757 } 2758 2759 /* Probably no EOLs here. */ 2760 if (memchr(pszContent, '\r', cchContent) == NULL) 2761 { 2762 *pchSecond = *pchFirst = 0; 2763 return 0; 2764 } 2765 2766 /* kind of unlikely */ 2767 *pchFirst = '\r'; 2768 *pchSecond = 0; 2769 return 1; 2770 } 2771 2772 2773 /** 2774 * Checks whether we've got an EOL escape sequence or not. 2775 * 2776 * @returns non-zero if escaped EOL, 0 if not (i.e. actual EOL). 2777 * @param pszContent The string pointer @a offEol is relative to. 2778 * @param offEol The offset of the first EOL char. 2779 */ 2780 static unsigned kmk_cc_eval_is_eol_escape_seq(const char *pszContent, size_t offEol) 2781 { 2782 /* The caller has already checked out two backslashes. */ 2783 size_t offFirstBackslash = offEol; 2784 KMK_CC_ASSERT(offFirstBackslash >= 2); 2785 offFirstBackslash -= 2; 2786 2787 /* Find the first backslash. */ 2788 while (offFirstBackslash > 0 && pszContent[offFirstBackslash - 1] == '\\') 2789 offFirstBackslash--; 2790 2791 /* Odd number -> escaped EOL; Even number -> real EOL; */ 2792 return (offEol - offFirstBackslash) & 1; 2793 } 2794 2795 2796 2797 typedef enum kmk_cc_eval_token 2798 { 2799 /** Invalid token . */ 2800 kKmkCcEvalToken_Invalid = 0, 2801 2802 /** Assignment: '=' */ 2803 kKmkCcEvalToken_AssignRecursive, 2804 /** Assignment: ':=' */ 2805 kKmkCcEvalToken_AssignSimple, 2806 /** Assignment: '+=' */ 2807 kKmkCcEvalToken_AssignAppend, 2808 /** Assignment: '<=' */ 2809 kKmkCcEvalToken_AssignPrepend, 2810 /** Assignment: '?=' */ 2811 kKmkCcEvalToken_AssignIfNew, 2812 /** Assignment: 'define' */ 2813 kKmkCcEvalToken_define, 2814 /** Unassignment: 'undefine' */ 2815 kKmkCcEvalToken_undefine, 2816 2817 /* Assignment modifier: 'local' */ 2818 kKmkCcEvalToken_local, 2819 /* Assignment modifier: 'override' */ 2820 kKmkCcEvalToken_override, 2821 /* Assignment modifier: 'private' (target variable not inh by deps) */ 2822 kKmkCcEvalToken_private, 2823 /* Assignment modifier / other variable thing: 'export' */ 2824 kKmkCcEvalToken_export, 2825 /* Other variable thing: 'unexport' */ 2826 kKmkCcEvalToken_unexport, 2827 2828 kKmkCcEvalToken_ifdef, 2829 kKmkCcEvalToken_ifndef, 2830 kKmkCcEvalToken_ifeq, 2831 kKmkCcEvalToken_ifneq, 2832 kKmkCcEvalToken_if1of, 2833 kKmkCcEvalToken_ifn1of, 2834 kKmkCcEvalToken_if, 2835 kKmkCcEvalToken_else, 2836 kKmkCcEvalToken_endif, 2837 2838 kKmkCcEvalToken_include, 2839 kKmkCcEvalToken_include_silent, 2840 kKmkCcEvalToken_includedep, 2841 kKmkCcEvalToken_includedep_queue, 2842 kKmkCcEvalToken_includedep_flush, 2843 2844 kKmkCcEvalToken_colon, 2845 kKmkCcEvalToken_double_colon, 2846 kKmkCcEvalToken_plus, 2847 kKmkCcEvalToken_plus_maybe, 2848 2849 kKmkCcEvalToken_vpath, 2850 2851 /** Plain word. */ 2852 kKmkCcEvalToken_WordPlain, 2853 /** Word that maybe in need of expanding. */ 2854 kKmkCcEvalToken_WordWithDollar, 2855 2856 kKmkCcEvalToken_End 2857 } KMKCCEVALTOKEN; 2858 2859 /** 2860 * A tokenized word. 2861 */ 2862 typedef struct kmk_cc_eval_word 2863 { 2864 /** The token word (lexeme). */ 2865 const char *pszWord; 2866 /** The length of the word (lexeme). */ 2867 uint32_t cchWord; 2868 /** The token classification. */ 2869 KMKCCEVALTOKEN enmToken; 2870 } KMKCCEVALWORD; 2871 typedef KMKCCEVALWORD *PKMKCCEVALWORD; 2872 2873 2874 /** 2875 * Escaped end-of-line sequence in the current line. 2876 * 2877 * This is initially noting down the start of the escape sequence and the EOL 2878 * marker. But after kmk_cc_eval_prep_command_line or 2879 * kmk_cc_eval_prep_normal_line it will change into copy instructions. The 2880 * offEsc is the end position of the current line, while offEol is the start of 2881 * the next line. If the next line doesn't contain anything to copy, offEsc 2882 * will contain the same value as offEol on the previous. 2883 */ 2884 typedef struct KMKCCEVALESCEOL 2885 { 2886 /** Offset at which the EOL escape sequence starts for a non-command line. 2887 * After prepping the line, this will be moved back to indicate the end of 2888 * the copy sequence for that line. */ 2889 size_t offEsc; 2890 /** Offset of the newline sequence. 2891 * After prepping the line, this will indicate where to start copying on the 2892 * following line. This may be the same as the offEsc in the next entry. */ 2893 size_t offEol; 2894 } KMKCCEVALESCEOL; 2895 typedef KMKCCEVALESCEOL *PKMKCCEVALESCEOL; 2896 2897 2898 typedef struct KMKCCEVALCOMPILER 2899 { 2900 /** Pointer to the KMKCCEVALPROG::pBlockTail member. */ 2901 PKMKCCBLOCK *ppBlockTail; 2902 2903 /** @name Line parsing state. 2904 * @{ */ 2905 /** Offset of newline escape sequences in the current line. 2906 * This is only applicable if cEscEols is not zero. */ 2907 PKMKCCEVALESCEOL paEscEols; 2908 /** The number of number of paEscEols entries we've allocated. */ 2909 unsigned cEscEolsAllocated; 2910 /** Number of escaped EOLs (line count - 1). */ 2911 unsigned cEscEols; 2912 /** The paEscEols entry corresponding to the current parsing location. 2913 * Still to be seen how accurate this can be made to be. */ 2914 unsigned iEscEol; 2915 2916 /** The current line number (for error handling / debugging). */ 2917 unsigned iLine; 2918 /** The start offset of the current line. */ 2919 size_t offLine; 2920 /** Length of the current line, sans the final EOL and comments. */ 2921 size_t cchLine; 2922 2923 /** The first char in an EOL sequence. 2924 * We ASSUMES that this char won't appear in any other sequence in the file, 2925 * thus skipping matching any subsequent chars. */ 2926 char chFirstEol; 2927 /** The second char in an EOL sequence, if applicable. */ 2928 char chSecondEol; 2929 2930 /** The length of the EOL sequence. */ 2931 size_t cchEolSeq; 2932 /** The minimum length of an esacped EOL sequence (cchEolSeq + 1). */ 2933 size_t cchEscEolSeq; 2934 /** @} */ 2935 2936 2937 /** @name Recipe state. 2938 * @{ */ 2939 /** Set if we're working on a recipe. */ 2940 PKMKCCEVALRECIPE pRecipe; 2941 /** Set for ignoring recipes without targets (Sun OS 4 Make). */ 2942 uint8_t fNoTargetRecipe; 2943 /** The command prefix character. */ 2944 char chCmdPrefix; 2945 /** @} */ 2946 2947 /** @name Tokenzied words. 2948 * @{ */ 2949 uint32_t cWords; 2950 uint32_t cWordsAllocated; 2951 PKMKCCEVALWORD paWords; 2952 /** @} */ 2953 2954 /** @name Conditionals. 2955 * @{ */ 2956 /** Current conditional stack depth. */ 2957 unsigned cIfs; 2958 /** The conditional directive stack. */ 2959 PKMKCCEVALIFCORE apIfs[KMK_CC_EVAL_MAX_IF_DEPTH]; 2960 /** @} */ 2961 2962 /** The program being compiled. */ 2963 PKMKCCEVALPROG pEvalProg; 2964 /** Pointer to the content. */ 2965 const char *pszContent; 2966 /** The amount of input to parse. */ 2967 size_t cchContent; 2968 } KMKCCEVALCOMPILER; 2969 typedef KMKCCEVALCOMPILER *PKMKCCEVALCOMPILER; 2970 2971 2972 static void kmk_cc_eval_init_compiler(PKMKCCEVALCOMPILER pCompiler, PKMKCCEVALPROG pEvalProg, unsigned iLine, 2973 const char *pszContent, size_t cchContent) 2974 { 2975 pCompiler->ppBlockTail = &pEvalProg->pBlockTail; 2976 2977 pCompiler->pRecipe = NULL; 2978 pCompiler->fNoTargetRecipe = 0; 2979 pCompiler->chCmdPrefix = cmd_prefix; 2980 2981 pCompiler->cWordsAllocated = 0; 2982 pCompiler->paWords = NULL; 2983 2984 pCompiler->cEscEolsAllocated = 0; 2985 pCompiler->paEscEols = NULL; 2986 pCompiler->iLine = iLine; 2987 2988 pCompiler->cIfs = 0; 2989 2990 pCompiler->pEvalProg = pEvalProg; 2991 pCompiler->pszContent = pszContent; 2992 pCompiler->cchContent = cchContent; 2993 2994 /* Detect EOL style. */ 2995 pCompiler->cchEolSeq = kmk_cc_eval_detect_eol_style(&pCompiler->chFirstEol, &pCompiler->chSecondEol, 2996 pszContent, cchContent); 2997 pCompiler->cchEscEolSeq = 1 + pCompiler->cchEolSeq; 2998 } 2999 3000 3001 static void kmk_cc_eval_delete_compiler(PKMKCCEVALCOMPILER pCompiler) 3002 { 3003 if (pCompiler->paWords) 3004 free(pCompiler->paWords); 3005 if (pCompiler->paEscEols) 3006 free(pCompiler->paEscEols); 3007 } 3008 3009 static void kmk_cc_eval_fatal(PKMKCCEVALCOMPILER pCompiler, const char *pchWhere, const char *pszMsg, ...) 3010 { 3011 va_list va; 3012 unsigned iLine = pCompiler->iLine; 3013 3014 log_working_directory(1); 3015 3016 /* 3017 * If we have a pointer location, use it to figure out the exact line and column. 3018 */ 3019 if (pchWhere) 3020 { 3021 size_t offLine = pCompiler->offLine; 3022 size_t off = pchWhere - pCompiler->pszContent; 3023 unsigned i = 0; 3024 while ( i < pCompiler->cEscEols 3025 && off > pCompiler->paEscEols[i].offEol) 3026 { 3027 offLine = pCompiler->paEscEols[i].offEol + 1 + pCompiler->cchEolSeq; 3028 iLine++; 3029 i++; 3030 } 3031 KMK_CC_ASSERT(off <= pCompiler->cchContent); 3032 3033 if (pCompiler->pEvalProg->pszVarName) 3034 fprintf(stderr, "%s:%u:%u: *** fatal parsing error in %s: ", 3035 pCompiler->pEvalProg->pszFilename, iLine, (unsigned)(off - offLine), pCompiler->pEvalProg->pszVarName); 3036 else 3037 fprintf(stderr, "%s:%u:%u: *** fatal parsing error: ", 3038 pCompiler->pEvalProg->pszFilename, iLine, (unsigned)(off - offLine)); 3039 } 3040 else if (pCompiler->pEvalProg->pszVarName) 3041 fprintf(stderr, "%s:%u: *** fatal parsing error in %s: ", 3042 pCompiler->pEvalProg->pszFilename, iLine, pCompiler->pEvalProg->pszVarName); 3043 else 3044 fprintf(stderr, "%s:%u: *** fatal parsing error: ", 3045 pCompiler->pEvalProg->pszFilename, iLine); 3046 3047 /* 3048 * Print the message and die. 3049 */ 3050 va_start(va, pszMsg); 3051 vfprintf(stderr, pszMsg, va); 3052 va_end(va); 3053 fputs(". Stop.\n", stderr); 3054 3055 for (;;) 3056 die(2); 3057 } 3058 3059 3060 static void kmk_cc_eval_fatal_eol(PKMKCCEVALCOMPILER pCompiler, const char *pchEol, unsigned iLine, size_t offLine) 3061 { 3062 pCompiler->iLine = iLine; 3063 pCompiler->offLine = offLine; 3064 3065 for (;;) 3066 kmk_cc_eval_fatal(pCompiler, pchEol, "Missing 2nd EOL character: found %#x instead of %#x\n", 3067 pchEol, pCompiler->chSecondEol); 3068 } 3069 3070 3071 3072 /** @name KMK_CC_WORD_COMP_CONST_XXX - Optimal(/insane) constant work matching. 3073 * @{ 3074 */ 3075 #if defined(KBUILD_ARCH_X86) || defined(KBUILD_ARCH_AMD64) /* Unaligned access is reasonably cheap. */ 3076 # define KMK_CC_WORD_COMP_CONST_0(a_pchLine, a_pszWord) (1) 3077 # define KMK_CC_WORD_COMP_CONST_2(a_pchLine, a_pszWord) \ 3078 ( *(uint16_t const *)(a_pchLine) == *(uint16_t const *)(a_pszWord) ) 3079 # define KMK_CC_WORD_COMP_CONST_3(a_pchLine, a_pszWord) \ 3080 ( *(uint16_t const *)(a_pchLine) == *(uint16_t const *)(a_pszWord) \ 3081 && (a_pchLine)[2] == (a_pszWord)[2] ) 3082 # define KMK_CC_WORD_COMP_CONST_4(a_pchLine, a_pszWord) \ 3083 ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) ) 3084 # define KMK_CC_WORD_COMP_CONST_5(a_pchLine, a_pszWord) \ 3085 ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) \ 3086 && (a_pchLine)[4] == (a_pszWord)[4] ) 3087 # define KMK_CC_WORD_COMP_CONST_6(a_pchLine, a_pszWord) \ 3088 ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) \ 3089 && ((uint16_t const *)(a_pchLine))[2] == ((uint32_t const *)(a_pszWord))[2] ) 3090 # define KMK_CC_WORD_COMP_CONST_7(a_pchLine, a_pszWord) \ 3091 ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) \ 3092 && ((uint16_t const *)(a_pchLine))[2] == ((uint32_t const *)(a_pszWord))[2] \ 3093 && (a_pchLine)[6] == (a_pszWord)[6] ) 3094 # define KMK_CC_WORD_COMP_CONST_8(a_pchLine, a_pszWord) \ 3095 ( *(uint64_t const *)(a_pchLine) == *(uint64_t const *)(a_pszWord) ) 3096 # define KMK_CC_WORD_COMP_CONST_10(a_pchLine, a_pszWord) \ 3097 ( *(uint64_t const *)(a_pchLine) == *(uint64_t const *)(a_pszWord) \ 3098 && ((uint16_t const *)(a_pchLine))[4] == ((uint16_t const *)(a_pszWord))[4] ) 3099 # define KMK_CC_WORD_COMP_CONST_16(a_pchLine, a_pszWord) \ 3100 ( *(uint64_t const *)(a_pchLine) == *(uint64_t const *)(a_pszWord) \ 3101 && ((uint64_t const *)(a_pchLine))[1] == ((uint64_t const *)(a_pszWord))[1] ) 3102 #else 3103 # define KMK_CC_WORD_COMP_CONST_0(a_pchLine, a_pszWord) (1) 3104 # define KMK_CC_WORD_COMP_CONST_2(a_pchLine, a_pszWord) \ 3105 ( (a_pchLine)[0] == (a_pszWord)[0] \ 3106 && (a_pchLine)[1] == (a_pszWord)[1] ) 3107 # define KMK_CC_WORD_COMP_CONST_3(a_pchLine, a_pszWord) \ 3108 ( (a_pchLine)[0] == (a_pszWord)[0] \ 3109 && (a_pchLine)[1] == (a_pszWord)[1] \ 3110 && (a_pchLine)[2] == (a_pszWord)[2] ) 3111 # define KMK_CC_WORD_COMP_CONST_4(a_pchLine, a_pszWord) \ 3112 ( (a_pchLine)[0] == (a_pszWord)[0] \ 3113 && (a_pchLine)[1] == (a_pszWord)[1] \ 3114 && (a_pchLine)[2] == (a_pszWord)[2] \ 3115 && (a_pchLine)[3] == (a_pszWord)[3] ) 3116 # define KMK_CC_WORD_COMP_CONST_5(a_pchLine, a_pszWord) \ 3117 ( (a_pchLine)[0] == (a_pszWord)[0] \ 3118 && (a_pchLine)[1] == (a_pszWord)[1] \ 3119 && (a_pchLine)[2] == (a_pszWord)[2] \ 3120 && (a_pchLine)[3] == (a_pszWord)[3] \ 3121 && (a_pchLine)[4] == (a_pszWord)[4] ) 3122 # define KMK_CC_WORD_COMP_CONST_6(a_pchLine, a_pszWord) \ 3123 ( (a_pchLine)[0] == (a_pszWord)[0] \ 3124 && (a_pchLine)[1] == (a_pszWord)[1] \ 3125 && (a_pchLine)[2] == (a_pszWord)[2] \ 3126 && (a_pchLine)[3] == (a_pszWord)[3] \ 3127 && (a_pchLine)[4] == (a_pszWord)[4] \ 3128 && (a_pchLine)[5] == (a_pszWord)[5] ) 3129 # define KMK_CC_WORD_COMP_CONST_7(a_pchLine, a_pszWord) \ 3130 ( (a_pchLine)[0] == (a_pszWord)[0] \ 3131 && (a_pchLine)[1] == (a_pszWord)[1] \ 3132 && (a_pchLine)[2] == (a_pszWord)[2] \ 3133 && (a_pchLine)[3] == (a_pszWord)[3] \ 3134 && (a_pchLine)[4] == (a_pszWord)[4] \ 3135 && (a_pchLine)[5] == (a_pszWord)[5] \ 3136 && (a_pchLine)[6] == (a_pszWord)[6] ) 3137 # define KMK_CC_WORD_COMP_CONST_8(a_pchLine, a_pszWord) \ 3138 ( (a_pchLine)[0] == (a_pszWord)[0] \ 3139 && (a_pchLine)[1] == (a_pszWord)[1] \ 3140 && (a_pchLine)[2] == (a_pszWord)[2] \ 3141 && (a_pchLine)[3] == (a_pszWord)[3] \ 3142 && (a_pchLine)[4] == (a_pszWord)[4] \ 3143 && (a_pchLine)[5] == (a_pszWord)[5] \ 3144 && (a_pchLine)[6] == (a_pszWord)[6] \ 3145 && (a_pchLine)[7] == (a_pszWord)[7] ) 3146 # define KMK_CC_WORD_COMP_CONST_10(a_pchLine, a_pszWord) \ 3147 ( (a_pchLine)[0] == (a_pszWord)[0] \ 3148 && (a_pchLine)[1] == (a_pszWord)[1] \ 3149 && (a_pchLine)[2] == (a_pszWord)[2] \ 3150 && (a_pchLine)[3] == (a_pszWord)[3] \ 3151 && (a_pchLine)[4] == (a_pszWord)[4] \ 3152 && (a_pchLine)[5] == (a_pszWord)[5] \ 3153 && (a_pchLine)[6] == (a_pszWord)[6] \ 3154 && (a_pchLine)[7] == (a_pszWord)[7] \ 3155 && (a_pchLine)[8] == (a_pszWord)[8] \ 3156 && (a_pchLine)[9] == (a_pszWord)[9] ) 3157 # define KMK_CC_WORD_COMP_CONST_16(a_pchLine, a_pszWord) \ 3158 ( (a_pchLine)[0] == (a_pszWord)[0] \ 3159 && (a_pchLine)[1] == (a_pszWord)[1] \ 3160 && (a_pchLine)[2] == (a_pszWord)[2] \ 3161 && (a_pchLine)[3] == (a_pszWord)[3] \ 3162 && (a_pchLine)[4] == (a_pszWord)[4] \ 3163 && (a_pchLine)[5] == (a_pszWord)[5] \ 3164 && (a_pchLine)[6] == (a_pszWord)[6] \ 3165 && (a_pchLine)[7] == (a_pszWord)[7] \ 3166 && (a_pchLine)[8] == (a_pszWord)[8] \ 3167 && (a_pchLine)[9] == (a_pszWord)[9] \ 3168 && (a_pchLine)[10] == (a_pszWord)[10] \ 3169 && (a_pchLine)[11] == (a_pszWord)[11] \ 3170 && (a_pchLine)[12] == (a_pszWord)[12] \ 3171 && (a_pchLine)[13] == (a_pszWord)[13] \ 3172 && (a_pchLine)[14] == (a_pszWord)[14] \ 3173 && (a_pchLine)[15] == (a_pszWord)[15]) 3174 #endif 3175 /** See if a starting of a given length starts with a constant word. */ 3176 #define KMK_CC_WORD_COMP_CONST(a_pCompiler, a_pchLine, a_cchLine, a_pszWord, a_cchWord) \ 3177 ( (a_cchLine) >= (a_cchWord) \ 3178 && ( (a_cchLine) == (a_cchWord) \ 3179 || KMK_CC_EVAL_IS_SPACE((a_pchLine)[a_cchWord]) \ 3180 || ((a_pchLine)[a_cchWord] == '\\' && (a_pchLine)[(a_cchWord) + 1] == (a_pCompiler)->chFirstEol) ) \ 3181 && KMK_CC_WORD_COMP_CONST_##a_cchWord(a_pchLine, a_pszWord) ) 3182 /** @} */ 3183 3184 3185 /** 3186 * Checks if a_ch is a space after a word. 3187 * 3188 * Since there is always a terminating zero, the user can safely access a char 3189 * beyond @a a_cchLeft. However, that byte isn't necessarily a zero terminator 3190 * character, so we have to check @a a_cchLeft whether we're at the end of the 3191 * parsing input string. 3192 * 3193 * @returns true / false. 3194 * @param a_pCompiler The compiler instance data. 3195 * @param a_ch The character to inspect. 3196 * @param a_ch2 The character following it, in case of escaped EOL. 3197 * @param a_cchLeft The number of chars left to parse (from @a a_ch). 3198 */ 3199 #define KMK_CC_EVAL_IS_SPACE_AFTER_WORD(a_pCompiler, a_ch, a_ch2, a_cchLeft) \ 3200 ( a_cchLeft == 0 \ 3201 || KMK_CC_EVAL_IS_SPACE(a_ch) \ 3202 || ((a_ch) == '\\' && (a_ch2) == (a_pCompiler)->chFirstEol) ) 3203 3204 /** 3205 * Used to skip spaces after a word. 3206 * 3207 * We ASSUME that the first char is a space or that we've reached the end of the 3208 * string (a_cchLeft == 0). 3209 * 3210 * @param a_pCompiler The compiler instance data. 3211 * @param a_pchWord The current input position, this will be moved to 3212 * the start of the next word or end of the input. 3213 * @param a_cchLeft The number of chars left to parse. This will be 3214 * updated. 3215 */ 3216 #define KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(a_pCompiler, a_pchWord, a_cchLeft) \ 3217 do { \ 3218 /* Skip the first char which is known to be a space, end of line or end of input. */ \ 3219 if ((a_cchLeft) > 0) \ 3220 { \ 3221 char const chSkipBlanksFirst = *(a_pchWord); \ 3222 KMK_CC_ASSERT(KMK_CC_EVAL_IS_SPACE_AFTER_WORD(a_pCompiler, chSkipBlanksFirst, (a_pchWord)[1], a_cchLeft)); \ 3223 if (chSkipBlanksFirst != '\\') \ 3224 { \ 3225 (a_pchWord) += 1; \ 3226 (a_cchLeft) -= 1; \ 3227 \ 3228 /* Another space or escaped EOL? Then there are probably more then, so call worker function. */ \ 3229 if ((a_cchLeft) > 0) \ 3230 { \ 3231 char const chSkipBlanksSecond = *(a_pchWord); \ 3232 if (KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(chSkipBlanksSecond)) \ 3233 (a_pchWord) = kmk_cc_eval_skip_spaces_after_word_slow(a_pchWord, &(a_cchLeft), \ 3234 chSkipBlanksSecond, a_pCompiler); \ 3235 } \ 3236 } \ 3237 else /* escape sequences can be complicated. */ \ 3238 (a_pchWord) = kmk_cc_eval_skip_spaces_after_word_slow(a_pchWord, &(a_cchLeft), \ 3239 chSkipBlanksFirst, a_pCompiler); \ 3240 } \ 3241 } while (0) 3242 3243 3244 //static int kmk_cc_eval_skip_esc_eol_slow(const char *pchWord, size_t cchLeft, PKMKCCEVALCOMPILER pCompiler, 3245 // const char **ppchWord, size_t *pcchLeft) 3246 //{ 3247 // KMK_CC_ASSERT(pchWord[0] == '\\'); 3248 // if (pCompiler->cEscEols) 3249 // { 3250 // size_t cchMin = 1 + pCompiler->chFirstEol; 3251 // if (cchLeft >= cchMin) 3252 // { 3253 // /* The simple case, no extra backslashes. */ 3254 // if (pchWord[1] == pCompiler->chFirstEol) 3255 // { 3256 // *pcchLeft = cchLeft - cchMin; 3257 // *pchWord = pchWord + cchMin; 3258 // return 1; 3259 // } 3260 // 3261 // /* The unlikly case, */ 3262 // 3263 // } 3264 // } 3265 // return 0; 3266 //} 3267 3268 3269 /** 3270 * The slow path of KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD. 3271 * 3272 * This is called to handles escaped EOL sequences, as these can involve 3273 * multiple backslashes and therefore doesn't led themselves well to inlined 3274 * code. 3275 * 3276 * The other case this is used for is to handle more than once space, since it's 3277 * likely that when there are two there might be more. No point in inlining 3278 * that, better do some loop unrolling instead. 3279 * 3280 * @returns Points to the first non-space character or end of input. 3281 * @param pchWord The current position. There is some kind of char 3282 * @param pcchLeft Pointer to the cchLeft variable, this is both 3283 * input and output. 3284 * @param ch The current character. 3285 * @param pCompiler The compiler instance data. 3286 */ 3287 static const char *kmk_cc_eval_skip_spaces_after_word_slow(const char *pchWord, size_t *pcchLeft, char ch, 3288 PKMKCCEVALCOMPILER pCompiler) 3289 { 3290 size_t cchLeft = *pcchLeft; 3291 3292 /* 3293 * Skip the pending space or EOL found by the caller. We need to 3294 * confirm the EOL. 3295 * 3296 * Note! We only need to care about simple backslash+EOL sequences here 3297 * since we're either at the end of a validated word, or we've already 3298 * skipped one space. In the former case, someone else has already 3299 * validated the escape esequence, in the latter case multiple 3300 * backslashes would indicate a new word that that we should return. 3301 */ 3302 if (ch != '\\') 3303 { 3304 pchWord += 1; 3305 cchLeft -= 1; 3306 } 3307 else if ( cchLeft >= pCompiler->cchEscEolSeq 3308 && pchWord[1] == pCompiler->chFirstEol) 3309 { 3310 KMK_CC_ASSERT(pCompiler->cchEolSeq == 1 || pchWord[2] == pCompiler->chSecondEol); 3311 pchWord += pCompiler->cchEscEolSeq; 3312 cchLeft -= pCompiler->cchEscEolSeq; 3313 pCompiler->iEscEol++; 3314 } 3315 else 3316 return pchWord; 3317 3318 /* 3319 * Skip further spaces. We unrolls 4 loops here. 3320 * ASSUMES cchEscEolSeq is either 2 or 3! 3321 */ 3322 KMK_CC_ASSERT(pCompiler->cchEscEolSeq == 2 || pCompiler->cchEscEolSeq == 3); 3323 while (cchLeft >= 4) 3324 { 3325 /* First char. */ 3326 ch = pchWord[0]; 3327 if (KMK_CC_EVAL_IS_SPACE(ch)) 3328 { /* maybe likely */ } 3329 else if ( ch == '\\' 3330 && pchWord[1] == pCompiler->chFirstEol) 3331 { 3332 pchWord += pCompiler->cchEscEolSeq; 3333 cchLeft -= pCompiler->cchEscEolSeq; 3334 pCompiler->iEscEol++; 3335 continue; 3336 } 3337 else 3338 { 3339 *pcchLeft = cchLeft; 3340 return pchWord; 3341 } 3342 3343 /* Second char. */ 3344 ch = pchWord[1]; 3345 if (KMK_CC_EVAL_IS_SPACE(ch)) 3346 { /* maybe likely */ } 3347 else if ( ch == '\\' 3348 && pchWord[2] == pCompiler->chFirstEol) 3349 { 3350 pchWord += 1 + pCompiler->cchEscEolSeq; 3351 cchLeft -= 1 + pCompiler->cchEscEolSeq; 3352 pCompiler->iEscEol++; 3353 continue; 3354 } 3355 else 3356 { 3357 *pcchLeft = cchLeft - 1; 3358 return pchWord + 1; 3359 } 3360 3361 /* Third char. */ 3362 ch = pchWord[2]; 3363 if (KMK_CC_EVAL_IS_SPACE(ch)) 3364 { /* maybe likely */ } 3365 else if ( ch == '\\' 3366 && pchWord[3] == pCompiler->chFirstEol 3367 && cchLeft >= 2 + pCompiler->cchEscEolSeq) 3368 { 3369 pchWord += 2 + pCompiler->cchEscEolSeq; 3370 cchLeft -= 2 + pCompiler->cchEscEolSeq; 3371 pCompiler->iEscEol++; 3372 continue; 3373 } 3374 else 3375 { 3376 *pcchLeft = cchLeft - 2; 3377 return pchWord + 2; 3378 } 3379 3380 /* Third char. */ 3381 ch = pchWord[3]; 3382 if (KMK_CC_EVAL_IS_SPACE(ch)) 3383 { 3384 pchWord += 4; 3385 cchLeft -= 4; 3386 } 3387 else if ( ch == '\\' 3388 && cchLeft >= 3 + pCompiler->cchEscEolSeq 3389 && pchWord[4] == pCompiler->chFirstEol) 3390 { 3391 pchWord += 3 + pCompiler->cchEscEolSeq; 3392 cchLeft -= 3 + pCompiler->cchEscEolSeq; 3393 pCompiler->iEscEol++; 3394 } 3395 else 3396 { 3397 *pcchLeft = cchLeft - 3; 3398 return pchWord + 3; 3399 } 3400 } 3401 3402 /* 3403 * Simple loop for the final three chars. 3404 */ 3405 while (cchLeft > 0) 3406 { 3407 /* First char. */ 3408 ch = *pchWord; 3409 if (KMK_CC_EVAL_IS_SPACE(ch)) 3410 { 3411 pchWord += 1; 3412 cchLeft -= 1; 3413 } 3414 else if ( ch == '\\' 3415 && cchLeft > pCompiler->cchEolSeq 3416 && pchWord[1] == pCompiler->chFirstEol) 3417 { 3418 pchWord += pCompiler->cchEscEolSeq; 3419 cchLeft -= pCompiler->cchEscEolSeq; 3420 pCompiler->iEscEol++; 3421 } 3422 else 3423 break; 3424 } 3425 3426 *pcchLeft = cchLeft; 3427 return pchWord; 3428 } 3429 3430 3431 #if 0 3432 /** 3433 * Used to shed trailing spaces in a string by decrementing @ a_cchLeft. 3434 * 3435 * @param a_pCompiler The compiler instance data. 3436 * @param a_pchWord The current input position, this will not be 3437 * changed. 3438 * @param a_cchLeft The number of chars left to parse. This will be 3439 * updated if there are trailing spaces. 3440 */ 3441 #define KMK_CC_EVAL_SHED_TRAILING_SPACES(a_pCompiler, a_pchWord, a_cchLeft) \ 3442 do { \ 3443 if ((a_cchLeft) > 0) \ 3444 { \ 3445 char const chShedTrailing1 = (a_pchWord)[(a_cchLeft) - 1]; \ 3446 if (KMK_CC_EVAL_IS_SPACE(chShedTrailing1)) \ 3447 { \ 3448 /* If there are two or more, or any of these are potential EOL chars, call worker. */ \ 3449 if (!KMK_CC_EVAL_IS_EOL_CANDIDATE(chShedTrailing1)) \ 3450 { \ 3451 (a_cchLeft) -= 1; \ 3452 if ((a_cchLeft) > 0) \ 3453 { \ 3454 char const chShedTrailing2 = (a_pchWord)[(a_cchLeft) - 1]; \ 3455 if (KMK_CC_EVAL_IS_SPACE(chShedTrailing)) \ 3456 (a_cchLeft) = kmk_cc_eval_shed_trailing_spaces_slow(a_pchWord, (a_cchLeft), \ 3457 chShedTrailing2, a_pCompiler); \ 3458 } \ 3459 } \ 3460 else \ 3461 (a_cchWord) = kmk_cc_eval_shed_trailing_spaces_slow(a_pchWord, (a_cchLeft), \ 3462 chShedTrailing1, a_pCompiler); \ 3463 } \ 3464 } \ 3465 } while (0) 3466 3467 3468 3469 /** 3470 * The slow path of KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD. 3471 * 3472 * It's called when a space or backslash is encountered as the 2nd character. 3473 * A second space is likely to be followed by more spaces, while an escaped 3474 * newline (if it checks out) is very likely to be followed by more spaces or 3475 * tabs before we get to anything worthwhile. Also, checking for an esacped 3476 * end-of-line character is a bit tedious. (It could be worse, though, as we 3477 * know that any EOL sequence inside the text area we're currently working on 3478 * must be escaped.) 3479 * 3480 * @returns Points to the first non-space character or end of input. 3481 * @param pchWord The current position. There is some kind of char 3482 * @param cchLeft The number of chars left to parse at @a pchWord. 3483 * @param ch The current tail character. 3484 * @param pCompiler The compiler instance data. 3485 */ 3486 static size_t kmk_cc_eval_shed_trailing_spaces_slow(const char *pchWord, size_t cchLeft, char ch, 3487 PKMKCCEVALCOMPILER pCompiler) 3488 { 3489 for (;;) 3490 { 3491 if (KMK_CC_EVAL_IS_EOL_CANDIDATE(chShedTrailing1)) 3492 { 3493 3494 } 3495 3496 } 3497 } 3498 #endif 3499 3500 3501 /** 3502 * Prepares for copying a command line. 3503 * 3504 * The current version of this code will not modify any of the paEscEols 3505 * entries, unlike our kmk_cc_eval_prep_normal_line sibling function. 3506 * 3507 * @returns The number of chars that will be copied by 3508 * kmk_cc_eval_copy_prepped_command_line(). 3509 * @param pCompiler The compiler instance data. 3510 * @param pchLeft Pointer to the first char to copy from the current line. 3511 * This does not have to the start of a word. 3512 * @param cchLeft The number of chars left on the current line starting at 3513 * @a pchLeft. 3514 */ 3515 static size_t kmk_cc_eval_prep_command_line(PKMKCCEVALCOMPILER pCompiler, const char * const pchLeft, size_t cchLeft) 3516 { 3517 size_t cchRet; 3518 unsigned iEscEol = pCompiler->iEscEol; 3519 unsigned const cEscEols = pCompiler->cEscEols; 3520 3521 KMK_CC_ASSERT(cchLeft > 0); 3522 KMK_CC_ASSERT(iEscEol <= cEscEols); 3523 3524 if (iEscEol >= cEscEols) 3525 { 3526 /* 3527 * No escaped EOLs left, dead simple. 3528 */ 3529 cchRet = cchLeft; 3530 } 3531 else 3532 { 3533 /* 3534 * Compared to the normal prepping of a line, this is actually 3535 * really simple. We need to account for two kind of conversions: 3536 * - One leading tab is skipped after escaped EOL. 3537 * - Convert EOL to LF. 3538 */ 3539 const char * const pszContent = pCompiler->pszContent; 3540 size_t const cchEolSeq = pCompiler->cchEolSeq; 3541 3542 #ifdef KMK_CC_STRICT 3543 size_t const offLeft = pchLeft - pszContent; 3544 KMK_CC_ASSERT(offLeft + cchLeft <= pCompiler->offLine + pCompiler->cchLine); 3545 KMK_CC_ASSERT(offLeft + cchLeft <= pCompiler->cchContent); 3546 KMK_CC_ASSERT(offLeft < pCompiler->paEscEols[iEscEol].offEsc); 3547 KMK_CC_ASSERT(offLeft >= (iEscEol ? pCompiler->paEscEols[cEscEols - 1].offEol + pCompiler->cchEolSeq : pCompiler->offLine)); 3548 #endif 3549 3550 cchRet = cchLeft; 3551 if (cchEolSeq > 1) 3552 cchRet -= (cchEolSeq - 1) * cEscEols; 3553 do 3554 { 3555 if (pszContent[pCompiler->paEscEols[cchEolSeq].offEol]) 3556 cchRet--; 3557 iEscEol++; 3558 } while (iEscEol < cEscEols); 3559 } 3560 return cchRet; 3561 } 3562 3563 3564 /** 3565 * Copies a command line to the buffer @a pszDst points to. 3566 * 3567 * Must only be used immediately after kmk_cc_eval_prep_command_line(). 3568 * 3569 * @returns 3570 * @param pCompiler The compiler instance data. 3571 * @param pchLeft Pointer to the first char to copy from the current line. 3572 * This does not have to the start of a word. 3573 * @param cchPrepped The return value of kmk_cc_eval_prep_command_line(). 3574 * @param pszDst The destination buffer, must be at least @a cchPrepped 3575 * plus one (terminator) char big. 3576 */ 3577 static void kmk_cc_eval_copy_prepped_command_line(PKMKCCEVALCOMPILER pCompiler, const char *pchLeft, 3578 size_t cchPrepped, char *pszDst) 3579 { 3580 unsigned iEscEol = pCompiler->iEscEol; 3581 unsigned const cEscEols = pCompiler->cEscEols; 3582 if (iEscEol >= cEscEols) 3583 { 3584 /* Single line. */ 3585 memcpy(pszDst, pchLeft, cchPrepped); 3586 pszDst[cchPrepped] = '\0'; 3587 } 3588 else 3589 { 3590 /* Multiple lines with normalized EOL and maybe one stripped leading TAB. */ 3591 char * const pszDstStart = pszDst; 3592 const char * const pszContent = pCompiler->pszContent; 3593 size_t const cchEolSeq = pCompiler->cchEolSeq; 3594 size_t offLeft = pchLeft - pCompiler->pszContent; 3595 size_t cchCopy; 3596 3597 do 3598 { 3599 size_t offEol = pCompiler->paEscEols[iEscEol].offEsc; 3600 cchCopy = offEol - offLeft; 3601 KMK_CC_ASSERT(offEol >= offLeft); 3602 3603 memcpy(pszDst, &pszContent[offLeft], cchCopy); 3604 pszDst += cchCopy; 3605 *pszDst += '\n'; 3606 3607 offLeft = offEol + cchEolSeq; 3608 if (pszContent[offLeft] == '\t') 3609 offLeft++; 3610 } while (iEscEol < cEscEols); 3611 3612 cchCopy = cchPrepped - (pszDst - pszDstStart); 3613 KMK_CC_ASSERT(cchCopy <= cchPrepped); 3614 memcpy(pszDst, &pszContent[offLeft], cchCopy); 3615 pszDst += cchCopy; 3616 3617 *pszDst = '\0'; 3618 KMK_CC_ASSERT(pszDst == &pszDstStart[cchPrepped]); 3619 } 3620 } 3621 3622 3623 /** 3624 * Prepares for copying a normal line. 3625 * 3626 * This will modify the members of paEscEols to store copy instructions for the 3627 * following kmk_cc_eval_copy_prepped_normal_line() call. 3628 * 3629 * @returns The number of chars that will be copied by 3630 * kmk_cc_eval_copy_prepped_normal_line(). 3631 * @param pCompiler The compiler instance data. 3632 * @param pchWord Pointer to the first char to copy from the 3633 * current line. This must be the start of a 3634 * word. 3635 * @param cchLeft The number of chars left on the current line 3636 * starting at @a pchWord. 3637 * @param fStripTrailingSpaces Whether to strip trailing spaces. 3638 */ 3639 static size_t kmk_cc_eval_prep_normal_line(PKMKCCEVALCOMPILER pCompiler, const char * const pchWord, size_t cchLeft, 3640 int fStripTrailingSpaces) 3641 { 3642 size_t cchRet; 3643 unsigned iEscEol = pCompiler->iEscEol; 3644 unsigned const cEscEols = pCompiler->cEscEols; 3645 3646 KMK_CC_ASSERT(cchLeft > 0); 3647 KMK_CC_ASSERT(!KMK_CC_EVAL_IS_SPACE(*pchWord)); /* The fact that we're standing at a word, is exploited below. */ 3648 KMK_CC_ASSERT(iEscEol <= cEscEols); 3649 3650 if (iEscEol >= cEscEols) 3651 { 3652 /* 3653 * No escaped EOLs left, simple. Just need to strip trailing spaces 3654 * when desired by the caller. 3655 */ 3656 cchRet = cchLeft; 3657 if (fStripTrailingSpaces) 3658 while (cchRet > 0 && KMK_CC_IS_SPACE_CH(pchWord[cchRet - 1])) 3659 cchRet--; 3660 } 3661 else 3662 { 3663 /* 3664 * This is a tad complicated. Working with offsets here is simpler. 3665 */ 3666 const char *pszContent = pCompiler->pszContent; 3667 size_t offWord = pchWord - pCompiler->pszContent; 3668 size_t offEsc; 3669 size_t fPendingSpace; 3670 3671 /* Go nuts checking our preconditions here. */ 3672 KMK_CC_ASSERT(offWord >= pCompiler->offLine); 3673 KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->offLine + pCompiler->cchLine); 3674 KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->cchContent); 3675 KMK_CC_ASSERT(offWord < pCompiler->paEscEols[iEscEol].offEsc); 3676 KMK_CC_ASSERT(offWord >= (iEscEol ? pCompiler->paEscEols[cEscEols - 1].offEol + pCompiler->cchEolSeq : pCompiler->offLine)); 3677 3678 /* First line - We're at the start of a word, so no left stripping needed. */ 3679 offEsc = pCompiler->paEscEols[iEscEol].offEsc; 3680 KMK_CC_ASSERT(offEsc > offWord); 3681 while (KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1])) 3682 offEsc--; 3683 KMK_CC_ASSERT(offEsc > offWord); 3684 3685 fPendingSpace = 1; 3686 cchRet = offEsc - offWord; 3687 pCompiler->paEscEols[iEscEol].offEsc = offEsc; 3688 3689 offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq; 3690 iEscEol++; 3691 3692 /* All but the last line. */ 3693 while (iEscEol < cEscEols) 3694 { 3695 offEsc = pCompiler->paEscEols[iEscEol].offEsc; 3696 while (offWord < offEsc && KMK_CC_EVAL_IS_SPACE(pszContent[offWord])) 3697 offWord++; 3698 3699 if (offWord < offEsc) 3700 { 3701 while (KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1])) 3702 offEsc--; 3703 cchRet += offEsc - offWord + fPendingSpace; 3704 fPendingSpace = 1; 3705 } 3706 3707 pCompiler->paEscEols[iEscEol - 1].offEol = offWord; 3708 pCompiler->paEscEols[iEscEol].offEsc = offEsc; 3709 3710 offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq; 3711 iEscEol++; 3712 } 3713 3714 /* Final line. We must calculate the end of line offset our selves here. */ 3715 offEsc = &pchWord[cchLeft] - pszContent; 3716 while (offWord < offEsc && KMK_CC_EVAL_IS_SPACE(pszContent[offWord])) 3717 offWord++; 3718 3719 if (offWord < offEsc) 3720 { 3721 if (fStripTrailingSpaces) 3722 while (KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1])) 3723 offEsc--; 3724 cchRet += offEsc - offWord + fPendingSpace; 3725 } 3726 pCompiler->paEscEols[iEscEol - 1].offEol = offWord; 3727 } 3728 return cchRet; 3729 } 3730 3731 3732 /** 3733 * Copies a normal line to the buffer @a pszDst points to. 3734 * 3735 * Must only be used immediately after kmk_cc_eval_prep_normal_line(). 3736 * 3737 * @param pCompiler The compiler instance data. 3738 * @param pchLeft Pointer to the first char to copy from the current line. 3739 * This does not have to the start of a word. 3740 * @param cchPrepped The return value of kmk_cc_eval_prep_normal_line(). 3741 * @param pszDst The destination buffer, must be at least @a cchPrepped 3742 * plus one (terminator) char big. 3743 */ 3744 static void kmk_cc_eval_copy_prepped_normal_line(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, 3745 size_t cchPrepped, char *pszDst) 3746 { 3747 unsigned iEscEol = pCompiler->iEscEol; 3748 unsigned const cEscEols = pCompiler->cEscEols; 3749 if (iEscEol >= cEscEols) 3750 { 3751 /* Single line. */ 3752 memcpy(pszDst, pchWord, cchPrepped); 3753 pszDst[cchPrepped] = '\0'; 3754 } 3755 else 3756 { 3757 /* offEsc = end of copy on a line, offWord/offEol is where to start on the next. */ 3758 size_t offWord = pchWord - pCompiler->pszContent; 3759 int fPendingSpace = 0; 3760 char * const pszDstStart = pszDst; 3761 size_t cchCopy; 3762 do 3763 { 3764 cchCopy = pCompiler->paEscEols[iEscEol].offEsc - offWord; 3765 KMK_CC_ASSERT(pCompiler->paEscEols[iEscEol].offEsc >= offWord); 3766 if (cchCopy) 3767 { 3768 if (fPendingSpace) 3769 *pszDst++ = ' '; 3770 memcpy(pszDst, &pCompiler->pszContent[offWord], cchCopy); 3771 pszDst += cchCopy; 3772 fPendingSpace = 1; 3773 } 3774 offWord = pCompiler->paEscEols[iEscEol].offEol; 3775 iEscEol++; 3776 } while (iEscEol < cEscEols); 3777 3778 /* The final line is delimited by cchPrepped. */ 3779 cchCopy = cchPrepped - (pszDst - pszDstStart); 3780 KMK_CC_ASSERT(cchCopy <= cchPrepped); 3781 if (cchCopy > 0) 3782 { 3783 if (fPendingSpace) 3784 *pszDst++ = ' '; 3785 memcpy(pszDst, &pCompiler->pszContent[offWord], cchCopy); 3786 pszDst += cchCopy; 3787 } 3788 *pszDst = '\0'; 3789 KMK_CC_ASSERT(pszDst == &pszDstStart[cchPrepped]); 3790 } 3791 } 3792 3793 3794 /** 3795 * Common worker for all kmk_cc_eval_do_if*() functions. 3796 * 3797 * @param pCompiler The compiler state. 3798 * @param pIfCore The new IF statement. 3799 * @param fInElse Set if this is an 'else if' (rather than just 'if'). 3800 */ 3801 static void kmk_cc_eval_do_if_core(PKMKCCEVALCOMPILER pCompiler, PKMKCCEVALIFCORE pIfCore, int fInElse) 3802 { 3803 unsigned iIf = pCompiler->cIfs; 3804 if (!fInElse) 3805 { 3806 /* Push an IF statement. */ 3807 if (iIf < KMK_CC_EVAL_MAX_IF_DEPTH) 3808 { 3809 pCompiler->cIfs = iIf + 1; 3810 pCompiler->apIfs[iIf] = pIfCore; 3811 pIfCore->pPrevCond = NULL; 3812 } 3813 else 3814 kmk_cc_eval_fatal(pCompiler, NULL, "Too deep IF nesting"); 3815 } 3816 else if (iIf > 0) 3817 { 3818 /* Link an IF statement. */ 3819 iIf--; 3820 pIfCore->pPrevCond = pCompiler->apIfs[iIf]; 3821 pCompiler->apIfs[iIf] = pIfCore; 3822 } 3823 else 3824 kmk_cc_eval_fatal(pCompiler, NULL, "'else if' without 'if'"); 3825 pIfCore->pNextTrue = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail); 3826 pIfCore->pNextFalse = NULL; /* This is set by else or endif. */ 3827 pIfCore->pTrueEndJump = NULL; /* This is set by else or endif. */ 3828 } 3829 3830 3831 /** 3832 * Deals with 'if expr' and 'else if expr' statements. 3833 * 3834 * @returns 1 to indicate we've handled a keyword (see 3835 * kmk_cc_eval_try_handle_keyword). 3836 * @param pCompiler The compiler state. 3837 * @param pchWord First char after 'define'. 3838 * @param cchLeft The number of chars left to parse on this line. 3839 * @param fInElse Set if this is an 'else if' (rather than just 'if'). 3840 */ 3841 static int kmk_cc_eval_do_if(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse) 3842 { 3843 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); 3844 if (cchLeft) 3845 { 3846 size_t cchExpr = kmk_cc_eval_prep_normal_line(pCompiler, pchWord, cchLeft, 1 /*fStripTrailingSpaces*/); 3847 PKMKCCEVALIFEXPR pInstr = (PKMKCCEVALIFEXPR)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, 3848 KMKCCEVALIFEXPR_SIZE(cchExpr)); 3849 kmk_cc_eval_copy_prepped_normal_line(pCompiler, pchWord, cchExpr, pInstr->szExpr); 3850 pInstr->cchExpr = cchExpr; 3851 pInstr->IfCore.Core.enmOpCode = kKmkCcEvalInstr_if; 3852 pInstr->IfCore.Core.iLine = pCompiler->iLine; 3853 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse); 3854 } 3855 else 3856 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive"); 3857 return 1; 3858 } 3859 3860 3861 static int kmk_cc_eval_do_ifdef(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt) 3862 { 3863 return 1; 3864 } 3865 3866 3867 static int kmk_cc_eval_do_ifeq(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt) 3868 { 3869 return 1; 3870 } 3871 3872 3873 static int kmk_cc_eval_do_if1of(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt) 3874 { 3875 return 1; 3876 } 3877 3878 3879 /** 3880 * Deals with 'else' and 'else ifxxx' statements. 3881 * 3882 * @returns 1 to indicate we've handled a keyword (see 3883 * kmk_cc_eval_try_handle_keyword). 3884 * @param pCompiler The compiler state. 3885 * @param pchWord First char after 'define'. 3886 * @param cchLeft The number of chars left to parse on this line. 3887 */ 3888 static int kmk_cc_eval_do_else(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft) 3889 { 3890 /* 3891 * There must be an 'if' on the stack. 3892 */ 3893 unsigned iIf = pCompiler->cIfs; 3894 if (iIf > 0) 3895 { 3896 PKMKCCEVALIFCORE pIfCore = pCompiler->apIfs[--iIf]; 3897 if (!pIfCore->pTrueEndJump) 3898 { 3899 /* Emit a jump instruction that will take us from the 'True' block to the 'endif'. */ 3900 PKMKCCEVALJUMP pInstr = (PKMKCCEVALJUMP)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); 3901 pInstr->Core.enmOpCode = kKmkCcEvalInstr_jump; 3902 pInstr->Core.iLine = pCompiler->iLine; 3903 pInstr->pNext = NULL; 3904 pIfCore->pTrueEndJump = pInstr; 3905 3906 /* The next instruction is the first in the 'False' block of the current 'if'. 3907 Should this be an 'else if', this will be the 'if' instruction emitted below. */ 3908 pIfCore->pNextFalse = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail); 3909 } 3910 else if (iIf == 0) 3911 kmk_cc_eval_fatal(pCompiler, pchWord, "2nd 'else' for 'if' at line %u", pIfCore->Core.iLine); 3912 else 3913 kmk_cc_eval_fatal(pCompiler, pchWord, "2nd 'else' in a row - missing 'endif' for 'if' at line %u?", 3914 pIfCore->Core.iLine); 3915 } 3916 else 3917 kmk_cc_eval_fatal(pCompiler, pchWord, "'else' without 'if'"); 3918 3919 /* 3920 * Check for 'else ifxxx'. There can be nothing else following an else. 3921 */ 3922 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); 3923 if (cchLeft) 3924 { 3925 if ( cchLeft > 2 3926 && KMK_CC_WORD_COMP_CONST_2(pchWord, "if")) 3927 { 3928 pchWord += 2; 3929 cchLeft -= 2; 3930 3931 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "", 0)) 3932 return kmk_cc_eval_do_if(pCompiler, pchWord, cchLeft, 1 /* in else */); 3933 3934 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "eq", 2)) 3935 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 2, cchLeft + 2, 1 /* in else */, 1 /* positive */); 3936 3937 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "def", 3)) 3938 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 3, cchLeft + 3, 1 /* in else */, 1 /* positive */); 3939 3940 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "neq", 3)) 3941 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 3, cchLeft + 3, 1 /* in else */, 0 /* positive */); 3942 3943 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "1of", 3)) 3944 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 3, cchLeft + 3, 1 /* in else */, 1 /* positive */); 3945 3946 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "ndef", 4)) 3947 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 4, cchLeft + 4, 1 /* in else */, 0 /* positive */); 3948 3949 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "n1of", 4)) 3950 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 4, cchLeft + 4, 1 /* in else */, 0 /* positive */); 3951 3952 pchWord -= 2; 3953 cchLeft += 2; 3954 } 3955 kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'else'"); 3956 } 3957 3958 return 1; 3959 } 3960 3961 3962 /** 3963 * Deals with the 'endif' statement. 3964 * 3965 * @returns 1 to indicate we've handled a keyword (see 3966 * kmk_cc_eval_try_handle_keyword). 3967 * @param pCompiler The compiler state. 3968 * @param pchWord First char after 'define'. 3969 * @param cchLeft The number of chars left to parse on this line. 3970 */ 3971 static int kmk_cc_eval_do_endif(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft) 3972 { 3973 /* 3974 * There must be an 'if' on the stack. We'll POP it. 3975 */ 3976 unsigned iIf = pCompiler->cIfs; 3977 if (iIf > 0) 3978 { 3979 PKMKCCEVALCORE pNextInstr; 3980 PKMKCCEVALIFCORE pIfCore = pCompiler->apIfs[--iIf]; 3981 pCompiler->cIfs = iIf; /* POP! */ 3982 3983 /* Update the jump targets for all IFs at this level. */ 3984 pNextInstr = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail); 3985 do 3986 { 3987 if (pIfCore->pTrueEndJump) 3988 { 3989 /* Make the true block jump here, to the 'endif'. The false block is already here. */ 3990 pIfCore->pTrueEndJump->pNext = pNextInstr; 3991 KMK_CC_ASSERT(pIfCore->pNextFalse); 3992 } 3993 else 3994 { 3995 /* No 'else'. The false-case jump here, to the 'endif'. */ 3996 KMK_CC_ASSERT(!pIfCore->pNextFalse); 3997 pIfCore->pNextFalse = pNextInstr; 3998 } 3999 4000 pIfCore = pIfCore->pPrevCond; 4001 } while (pIfCore); 4002 } 4003 else 4004 kmk_cc_eval_fatal(pCompiler, pchWord, "'endif' without 'if'"); 4005 4006 /* 4007 * There shouldn't be anything trailing an 'endif'. 4008 */ 4009 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); 4010 if (!cchLeft) { /* likely */ } 4011 else kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'else'"); 4012 4013 return 1; 4014 } 4015 4016 4017 static int kmk_cc_eval_do_include(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, KMKCCEVALINSTR enmInst) 4018 { 4019 return 1; 4020 } 4021 4022 4023 static int kmk_cc_eval_do_vpath(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft) 4024 { 4025 return 1; 4026 } 4027 4028 4029 static void kmk_cc_eval_handle_command(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft) 4030 { 4031 4032 } 4033 4034 4035 static void kmk_cc_eval_handle_recipe(PKMKCCEVALCOMPILER pCompiler, const char *pszEqual, const char *pchWord, size_t cchLeft) 4036 { 4037 4038 } 4039 4040 4041 /** 4042 * Parses a 'undefine variable [..]' expression. 4043 * 4044 * A 'undefine' directive is final, any qualifiers must preceed it. So, we just 4045 * have to extract the variable names now. 4046 * 4047 * @returns 1 to indicate we've handled a keyword (see 4048 * kmk_cc_eval_try_handle_keyword). 4049 * @param pCompiler The compiler state. 4050 * @param pchWord First char after 'define'. 4051 * @param cchLeft The number of chars left to parse on this line. 4052 * @param fQualifiers The qualifiers. 4053 */ 4054 static int kmk_cc_eval_do_var_undefine(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, 4055 unsigned fQualifiers) 4056 { 4057 4058 return 1; 4059 } 4060 4061 4062 /** 4063 * Parses a 'define variable' expression. 4064 * 4065 * A 'define' directive is final, any qualifiers must preceed it. So, we just 4066 * have to extract the variable name now, well and find the corresponding 4067 * 'endef'. 4068 * 4069 * @returns 1 to indicate we've handled a keyword (see 4070 * kmk_cc_eval_try_handle_keyword). 4071 * @param pCompiler The compiler state. 4072 * @param pchWord First char after 'define'. 4073 * @param cchLeft The number of chars left to parse on this line. 4074 * @param fQualifiers The qualifiers. 4075 */ 4076 static int kmk_cc_eval_do_var_define(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, 4077 unsigned fQualifiers) 4078 { 4079 4080 return 1; 4081 } 4082 4083 4084 static int kmk_cc_eval_try_handle_assignment(PKMKCCEVALCOMPILER pCompiler, const char *pchTmp, 4085 const char *pchWord, size_t cchLeft, unsigned fQualifiers) 4086 { 4087 return 0; 4088 } 4089 4090 4091 /** 4092 * Parses a 'local [override] variable = value' expression. 4093 * 4094 * The 'local' directive must be first and it does not permit any qualifiers at 4095 * the moment. Should any be added later, they will have to come after 'local'. 4096 * 4097 * @returns 1 to indicate we've handled a keyword (see 4098 * kmk_cc_eval_try_handle_keyword). 4099 * @param pCompiler The compiler state. 4100 * @param pchWord First char after 'define'. 4101 * @param cchLeft The number of chars left to parse on this line. 4102 * @param fQualifiers The qualifiers. 4103 */ 4104 static int kmk_cc_eval_do_var_local(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft) 4105 { 4106 4107 return 1; 4108 } 4109 4110 4111 /** 4112 * Parses 'export [variable]' and 'export [qualifiers] variable = value' 4113 * expressions. 4114 * 4115 * When we find the 'export' directive at the start of a line, we need to 4116 * continue parsing with till we can tell the difference between the two forms. 4117 * 4118 * @returns 1 to indicate we've handled a keyword (see 4119 * kmk_cc_eval_try_handle_keyword). 4120 * @param pCompiler The compiler state. 4121 * @param pchWord First char after 'define'. 4122 * @param cchLeft The number of chars left to parse on this line. 4123 * @param fQualifiers The qualifiers. 4124 */ 4125 static int kmk_cc_eval_handle_var_export(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, 4126 unsigned fQualifiers) 4127 { 4128 4129 return 1; 4130 } 4131 4132 4133 /** 4134 * We've found one variable qualification keyword, now continue parsing and see 4135 * if this is some kind of variable assignment expression or not. 4136 * 4137 * @returns 1 if variable assignment, 0 if not. 4138 * @param pCompiler The compiler state. 4139 * @param pchWord First char after the first qualifier. 4140 * @param cchLeft The number of chars left to parse on this line. 4141 * @param fQualifiers The qualifier. 4142 */ 4143 static int kmk_cc_eval_try_handle_var_with_keywords(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, 4144 unsigned fQualifiers) 4145 { 4146 for (;;) 4147 { 4148 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); 4149 if (cchLeft) 4150 { 4151 char ch = *pchWord; 4152 if (KMK_CC_EVAL_IS_1ST_IN_VARIABLE_KEYWORD(ch)) 4153 { 4154 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6)) /* final */ 4155 return kmk_cc_eval_do_var_define(pCompiler, pchWord + 6, cchLeft - 6, fQualifiers); 4156 4157 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6)) /* special */ 4158 return kmk_cc_eval_handle_var_export(pCompiler, pchWord + 6, cchLeft - 6, fQualifiers); 4159 4160 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8)) /* final */ 4161 return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 6, cchLeft - 6, fQualifiers); 4162 4163 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8)) 4164 { 4165 /** @todo warn if repeated. */ 4166 fQualifiers |= KMK_CC_EVAL_QUALIFIER_OVERRIDE; 4167 pchWord += 8; 4168 cchLeft -= 8; 4169 continue; 4170 } 4171 4172 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7)) 4173 { 4174 /** @todo warn if repeated. */ 4175 fQualifiers |= KMK_CC_EVAL_QUALIFIER_PRIVATE; 4176 pchWord += 7; 4177 cchLeft -= 7; 4178 continue; 4179 } 4180 } 4181 4182 /* 4183 * Not a keyword, likely variable name followed by an assignment 4184 * operator and a value. Do a rough check for the assignment operator 4185 * and join paths with the unqualified assignment handling code. 4186 */ 4187 { 4188 const char *pchEqual = (const char *)memchr(pchWord, '=', cchLeft); 4189 if (pchEqual) 4190 return kmk_cc_eval_try_handle_assignment(pCompiler, pchEqual, pchWord, cchLeft, fQualifiers); 4191 } 4192 return 0; 4193 } 4194 else 4195 kmk_cc_eval_fatal(pCompiler, NULL, 4196 "Expected assignment operator or variable directive after variable qualifier(s)\n"); 4197 } 4198 } 4199 4200 4201 /** 4202 * When entering this function we know that the first two character in the first 4203 * word both independently occurs in keywords. 4204 * 4205 * @returns 1 if make directive or qualified variable assignment, 0 if neither. 4206 * @param pCompiler The compiler state. 4207 * @param ch The first char. 4208 * @param pchWord Pointer to the first word. 4209 * @param cchLeft Number of characters left to parse starting at 4210 * @a cchLeft. 4211 */ 4212 int kmk_cc_eval_try_handle_keyword(PKMKCCEVALCOMPILER pCompiler, char ch, const char *pchWord, size_t cchLeft) 4213 { 4214 unsigned iSavedEscEol = pCompiler->iEscEol; 4215 4216 KMK_CC_ASSERT(cchLeft >= 2); 4217 KMK_CC_ASSERT(ch == pchWord[0]); 4218 KMK_CC_ASSERT(KMK_CC_EVAL_IS_1ST_IN_KEYWORD(pchWord[0])); 4219 KMK_CC_ASSERT(KMK_CC_EVAL_IS_2ND_IN_KEYWORD(pchWord[1])); 4220 4221 /* 4222 * If it's potentially a variable related keyword, check that out first. 4223 */ 4224 if (KMK_CC_EVAL_IS_1ST_IN_VARIABLE_KEYWORD(ch)) 4225 { 4226 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "local", 5)) 4227 return kmk_cc_eval_do_var_local(pCompiler, pchWord + 5, cchLeft - 5); 4228 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6)) 4229 return kmk_cc_eval_do_var_define(pCompiler, pchWord + 6, cchLeft - 6, 0); 4230 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6)) 4231 return kmk_cc_eval_handle_var_export(pCompiler, pchWord + 6, cchLeft - 6, 0); 4232 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8)) 4233 return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 8, cchLeft - 8, 0); 4234 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8)) 4235 { 4236 if (kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord + 8, cchLeft - 8, KMK_CC_EVAL_QUALIFIER_OVERRIDE)) 4237 return 1; 4238 pCompiler->iEscEol = iSavedEscEol; 4239 } 4240 else if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7)) 4241 { 4242 if (kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord + 7, cchLeft - 7, KMK_CC_EVAL_QUALIFIER_PRIVATE)) 4243 return 1; 4244 pCompiler->iEscEol = iSavedEscEol; 4245 } 4246 } 4247 4248 /* 4249 * Check out the other keywords. 4250 */ 4251 if (ch == 'i') /* Lots of directives starting with 'i'. */ 4252 { 4253 char ch2 = pchWord[1]; 4254 pchWord += 2; 4255 cchLeft -= 2; 4256 4257 /* 'if...' */ 4258 if (ch2 == 'f') 4259 { 4260 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "", 0)) 4261 return kmk_cc_eval_do_if(pCompiler, pchWord, cchLeft, 0 /* in else */); 4262 4263 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "eq", 2)) 4264 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 2, cchLeft + 2, 0 /* in else */, 1 /* positive */); 4265 4266 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "def", 3)) 4267 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 3, cchLeft + 3, 0 /* in else */, 1 /* positive */); 4268 4269 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "neq", 3)) 4270 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 3, cchLeft + 3, 0 /* in else */, 0 /* positive */); 4271 4272 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "1of", 3)) 4273 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 3, cchLeft + 3, 0 /* in else */, 1 /* positive */); 4274 4275 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "ndef", 4)) 4276 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 4, cchLeft + 4, 0 /* in else */, 0 /* positive */); 4277 4278 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "n1of", 4)) 4279 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 4, cchLeft + 4, 0 /* in else */, 0 /* positive */); 4280 } 4281 /* include... */ 4282 else if (ch2 == 'n' && cchLeft >= 5 && KMK_CC_WORD_COMP_CONST_5(pchWord, "clude") ) /* 'in...' */ 4283 { 4284 pchWord += 5; 4285 cchLeft -= 5; 4286 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "", 0)) 4287 return kmk_cc_eval_do_include(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_include); 4288 if (cchLeft >= 3 && KMK_CC_WORD_COMP_CONST_3(pchWord, "dep")) 4289 { 4290 pchWord += 3; 4291 cchLeft -= 3; 4292 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "", 0)) 4293 return kmk_cc_eval_do_include(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_includedep); 4294 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-queue", 6)) 4295 return kmk_cc_eval_do_include(pCompiler, pchWord + 6, cchLeft + 6, kKmkCcEvalInstr_includedep_queue); 4296 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-flush", 6)) 4297 return kmk_cc_eval_do_include(pCompiler, pchWord + 6, cchLeft + 6, kKmkCcEvalInstr_includedep_flush); 4298 } 4299 } 4300 } 4301 else if (ch == 'e') /* A few directives starts with 'e'. */ 4302 { 4303 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "else", 4)) 4304 return kmk_cc_eval_do_else(pCompiler, pchWord + 4, cchLeft + 4); 4305 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "endif", 5)) 4306 return kmk_cc_eval_do_endif(pCompiler, pchWord + 5, cchLeft + 5); 4307 /* export and endef are handled elsewhere, though stray endef's may end up here... */ 4308 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6)); 4309 4310 } 4311 else /* the rest. */ 4312 { 4313 if ( KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "sinclude", 8) 4314 || KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-include", 8)) 4315 return kmk_cc_eval_do_include(pCompiler, pchWord + 8, cchLeft + 8, kKmkCcEvalInstr_include_silent); 4316 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "vpath", 5)) 4317 return kmk_cc_eval_do_vpath(pCompiler, pchWord + 5, cchLeft + 5); 4318 4319 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "local", 5)); 4320 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6)); 4321 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7)); 4322 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8)); 4323 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "unexport", 8)); 4324 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8)); 4325 } 4326 4327 pCompiler->iEscEol = iSavedEscEol; 4328 return 0; 4329 } 4330 4331 4332 4333 4334 static int kmk_cc_eval_compile_worker(PKMKCCEVALPROG pEvalProg, const char *pszContent, size_t cchContent, unsigned iLine) 4335 { 4336 const char *pchTmp; 4337 4338 /* 4339 * Compiler state. 4340 */ 4341 KMKCCEVALCOMPILER Compiler; 4342 kmk_cc_eval_init_compiler(&Compiler, pEvalProg, iLine, pszContent, cchContent); 4343 4344 { 4345 /* 4346 * Line state. 4347 */ 4348 size_t cchLine; /* The length of the current line (w/o comments). */ 4349 size_t offNext = 0; /* The offset of the next line. */ 4350 size_t off = 0; /* The offset into pszContent of the current line. */ 4351 4352 /* Try for some register/whatever optimzations. */ 4353 int const chFirstEol = Compiler.chFirstEol; 4354 size_t const cchEolSeq = Compiler.cchEolSeq; 4355 4356 /* 4357 * Process input lines. 4358 * 4359 * The code here concerns itself with getting the next line in an efficient 4360 * manner, very basic classification and trying out corresponding handlers. 4361 * The real work is done in the handlers. 4362 */ 4363 while (offNext < cchContent) 4364 { 4365 size_t offFirstWord; 4366 4367 /* 4368 * Find the end of the next line. 4369 */ 4370 KMK_CC_ASSERT(off == offNext); 4371 4372 /* Simple case: No escaped EOL, nor the end of the input. */ 4373 pchTmp = (const char *)memchr(&pszContent[offNext], chFirstEol, cchContent - offNext); 4374 if (pchTmp && (&pszContent[offNext] == pchTmp || pchTmp[-1] != '\\') ) 4375 { 4376 if ( cchEolSeq == 1 4377 || pchTmp[1] == Compiler.chSecondEol) 4378 { 4379 /* Frequent: Blank line or comment line. Skip. */ 4380 if ( &pszContent[offNext] == pchTmp 4381 || pszContent[offNext] == '#') 4382 { 4383 iLine++; 4384 off = offNext += cchEolSeq; 4385 continue; 4386 } 4387 4388 cchLine = pchTmp - pszContent; 4389 offNext = cchLine + cchEolSeq; 4390 Compiler.cEscEols = 0; 4391 Compiler.iEscEol = 0; 4392 4393 offFirstWord = off; 4394 while (offFirstWord < cchLine && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord])) 4395 offFirstWord++; 4396 } 4397 else 4398 kmk_cc_eval_fatal_eol(&Compiler, pchTmp, iLine, off); 4399 } 4400 /* The complicated, less common cases. */ 4401 else 4402 { 4403 Compiler.cEscEols = 0; 4404 Compiler.iEscEol = 0; 4405 offFirstWord = offNext; 4406 for (;;) 4407 { 4408 if (offFirstWord == offNext) 4409 while (offFirstWord < cchLine && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord])) 4410 offFirstWord++; 4411 4412 if (pchTmp) 4413 { 4414 if ( cchEolSeq == 1 4415 || pchTmp[1] == Compiler.chSecondEol) 4416 { 4417 size_t offEsc; 4418 offNext = pchTmp - pszContent; 4419 4420 /* Is it an escape sequence? */ 4421 if ( !offNext 4422 || pchTmp[-1] != '\\') 4423 { 4424 cchLine = offNext - off; 4425 offNext += cchEolSeq; 4426 break; 4427 } 4428 if (offNext < 2 || pchTmp[-2] != '\\') 4429 offEsc = offNext - 1; 4430 else 4431 { 4432 /* Count how many backslashes there are. Must be odd number to be an escape 4433 sequence. Normally we keep half of them, except for command lines. */ 4434 size_t cSlashes = 2; 4435 while (offNext >= cSlashes && pchTmp[0 - cSlashes] == '\\') 4436 cSlashes--; 4437 if (!(cSlashes & 1)) 4438 { 4439 cchLine = offNext - off; 4440 offNext += cchEolSeq; 4441 break; 4442 } 4443 offEsc = offNext - (cSlashes >> 1); 4444 } 4445 4446 /* Record it. */ 4447 if (Compiler.cEscEols < Compiler.cEscEolsAllocated) { /* likely */ } 4448 else 4449 { 4450 KMK_CC_ASSERT(Compiler.cEscEols == Compiler.cEscEolsAllocated); 4451 Compiler.cEscEolsAllocated = Compiler.cEscEolsAllocated 4452 ? Compiler.cEscEolsAllocated * 2 : 2; 4453 Compiler.paEscEols = (PKMKCCEVALESCEOL)xrealloc(Compiler.paEscEols, 4454 Compiler.cEscEolsAllocated 4455 * sizeof(Compiler.paEscEols[0])); 4456 } 4457 Compiler.paEscEols[Compiler.cEscEols].offEsc = offEsc; 4458 Compiler.paEscEols[Compiler.cEscEols].offEol = offNext; 4459 Compiler.cEscEols++; 4460 4461 /* Advance. */ 4462 offNext += cchEolSeq; 4463 if (offFirstWord == offEsc) 4464 { 4465 offFirstWord = offNext; 4466 Compiler.iEscEol++; 4467 } 4468 } 4469 else 4470 kmk_cc_eval_fatal_eol(&Compiler, pchTmp, iLine, off); 4471 } 4472 else 4473 { 4474 /* End of input. Happens only once per compilation, nothing to optimize for. */ 4475 offNext = cchContent; 4476 cchLine = cchContent - off; 4477 break; 4478 } 4479 pchTmp = (const char *)memchr(&pszContent[offNext], chFirstEol, cchContent - offNext); 4480 } 4481 } 4482 KMK_CC_ASSERT(offNext <= cchContent); 4483 KMK_CC_ASSERT(off + cchLine <= cchContent && cchLine <= cchContent); 4484 KMK_CC_ASSERT(offFirstWord <= cchLine); 4485 KMK_CC_ASSERT(offFirstWord >= off); 4486 KMK_CC_ASSERT(pszContent[offFirstWord] != ' ' && pszContent[offFirstWord] != '\t'); 4487 4488 /* 4489 * Check for comments and skip blank lines. 4490 */ 4491 if ( offFirstWord < cchLine 4492 && pszContent[offFirstWord] != '#') 4493 { 4494 const char *pchWord = &pszContent[offFirstWord]; 4495 size_t cchLeft = cchLine - offFirstWord; 4496 pchTmp = (const char *)memchr(pchWord, '#', cchLeft); /** @todo not correct for command lines! */ 4497 if (pchTmp) 4498 { 4499 cchLeft = pchTmp - pchWord; 4500 cchLine = pchTmp - &pszContent[off]; 4501 } 4502 4503 /* 4504 * Update the compiler state that we pass around. 4505 */ 4506 Compiler.iLine = iLine; 4507 Compiler.offLine = off; 4508 Compiler.cchLine = cchLine; 4509 4510 /* 4511 * Command? Ignore command prefix if no open recipe (SunOS 4 behavior). 4512 */ 4513 if ( pszContent[off] == Compiler.chCmdPrefix 4514 && (Compiler.pRecipe || Compiler.fNoTargetRecipe)) 4515 { 4516 if (!Compiler.fNoTargetRecipe) 4517 kmk_cc_eval_handle_command(&Compiler, &pszContent[off], cchLine); 4518 } 4519 else 4520 { 4521 /* 4522 * If not a directive or variable qualifier, it's either a variable 4523 * assignment or a recipe. 4524 */ 4525 char ch = *pchWord; 4526 if ( !KMK_CC_EVAL_IS_1ST_IN_KEYWORD(ch) 4527 || !KMK_CC_EVAL_IS_2ND_IN_KEYWORD(pchWord[1]) 4528 || !kmk_cc_eval_try_handle_keyword(&Compiler, ch, pchWord, cchLeft) ) 4529 { 4530 pchTmp = (const char *)memchr(pchWord, '=', cchLeft); 4531 if ( !pchTmp 4532 || !kmk_cc_eval_try_handle_assignment(&Compiler, pchTmp, pchWord, cchLeft, 0) ) 4533 kmk_cc_eval_handle_recipe(&Compiler, pchTmp, pchWord, cchLeft); 4534 } 4535 /* else: handled a keyword expression */ 4536 } 4537 } 4538 4539 /* 4540 * Advance to the next line. 4541 */ 4542 off = offNext; 4543 iLine += Compiler.cEscEols + 1; 4544 } 4545 } 4546 4547 /* 4548 * Check whether 4549 */ 4550 4551 kmk_cc_eval_delete_compiler(&Compiler); 4552 return 0; 4553 } 4554 4555 2441 4556 /*#define KMK_CC_EVAL_ENABLE*/ 4557 4558 static PKMKCCEVALPROG kmk_cc_eval_compile(const char *pszContent, size_t cchContent, 4559 const char *pszFilename, unsigned iLine, const char *pszVarName) 4560 { 4561 /* 4562 * Estimate block size, allocate one and initialize it. 4563 */ 4564 PKMKCCEVALPROG pEvalProg; 4565 PKMKCCBLOCK pBlock; 4566 pEvalProg = kmk_cc_block_alloc_first(&pBlock, sizeof(*pEvalProg), cchContent / 32); /** @todo adjust */ 4567 if (pEvalProg) 4568 { 4569 int rc = 0; 4570 4571 pEvalProg->pBlockTail = pBlock; 4572 pEvalProg->pFirstInstr = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(pBlock); 4573 pEvalProg->pszFilename = pszFilename ? pszFilename : "<unknown>"; 4574 pEvalProg->pszVarName = pszVarName; 4575 pEvalProg->cRefs = 1; 4576 #ifdef KMK_CC_STRICT 4577 pEvalProg->uInputHash = kmk_cc_debug_string_hash_n(0, pszContent, cchContent); 4578 #endif 4579 4580 /* 4581 * Do the actual compiling. 4582 */ 4583 #ifdef KMK_CC_EVAL_ENABLE 4584 if (kmk_cc_eval_compile_worker(pEvalProg, pszContent, cchContent, iLine) == 0) 4585 #else 4586 if (0) 4587 #endif 4588 { 4589 #ifdef KMK_CC_WITH_STATS 4590 pBlock = pEvalProg->pBlockTail; 4591 if (!pBlock->pNext) 4592 g_cSingleBlockEvalProgs++; 4593 else if (!pBlock->pNext->pNext) 4594 g_cTwoBlockEvalProgs++; 4595 else 4596 g_cMultiBlockEvalProgs++; 4597 for (; pBlock; pBlock = pBlock->pNext) 4598 { 4599 g_cBlocksAllocatedEvalProgs++; 4600 g_cbAllocatedEvalProgs += pBlock->cbBlock; 4601 g_cbUnusedMemEvalProgs += pBlock->cbBlock - pBlock->offNext; 4602 } 4603 #endif 4604 return pEvalProg; 4605 } 4606 kmk_cc_block_free_list(pEvalProg->pBlockTail); 4607 } 4608 return NULL; 4609 } 2442 4610 2443 4611 … … 2450 4618 struct kmk_cc_evalprog *kmk_cc_compile_variable_for_eval(struct variable *pVar) 2451 4619 { 2452 return NULL; 4620 PKMKCCEVALPROG pEvalProg = pVar->evalprog; 4621 if (!pEvalProg) 4622 { 4623 #ifdef KMK_CC_EVAL_ENABLE 4624 pEvalProg = kmk_cc_eval_compile(pVar->value, pVar->value_length, 4625 pVar->fileinfo.filenm, pVar->fileinfo.lineno, pVar->name); 4626 pVar->evalprog = pEvalProg; 4627 #endif 4628 g_cVarForEvalCompilations++; 4629 } 4630 return pEvalProg; 2453 4631 } 2454 4632 … … 2462 4640 struct kmk_cc_evalprog *kmk_cc_compile_file_for_eval(FILE *pFile, const char *pszFilename) 2463 4641 { 2464 #ifdef KMK_CC_EVAL_ENABLE 4642 PKMKCCEVALPROG pEvalProg; 4643 2465 4644 /* 2466 4645 * Read the entire file into a zero terminate memory buffer. 2467 4646 */ 2468 size_t cchContent = 0;2469 char *pszContent = NULL;4647 size_t cchContent = 0; 4648 char *pszContent = NULL; 2470 4649 struct stat st; 2471 4650 if (!fstat(fileno(pFile), &st)) … … 2500 4679 * Call common function to do the compilation. 2501 4680 */ 2502 //kmk_cc_eval_compile_common() 4681 pEvalProg = kmk_cc_eval_compile(pszContent, cchContent, pszFilename, 1, NULL /*pszVarName*/); 4682 g_cFileForEvalCompilations++; 2503 4683 2504 4684 free(pszContent); 2505 return NULL; 2506 #else 2507 return NULL; 2508 #endif 4685 if (!pEvalProg) 4686 fseek(pFile, 0, SEEK_SET); 4687 return pEvalProg; 2509 4688 } 2510 4689
Note:
See TracChangeset
for help on using the changeset viewer.