VirtualBox

Changeset 2801 in kBuild for trunk


Ignore:
Timestamp:
Sep 20, 2015 7:13:24 PM (9 years ago)
Author:
bird
Message:

kmk_cc_exec.c: More code.

Location:
trunk/src/kmk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk/Makefile.kmk

    r2799 r2801  
    209209 kmk_DEFS += CONFIG_WITH_EVAL_COMPILER
    210210endif
    211 ifdef CONFIG_WITH_COMPILER
     211ifdef CONFIG_WITH_COMPILE_EVERYTHING
    212212 kmk_DEFS += CONFIG_WITH_COMPILE_EVERYTHING
    213213endif
  • trunk/src/kmk/kmk_cc_exec.c

    r2799 r2801  
    121121
    122122
    123 /** @def KMK_CC_IS_SPACE_CH
    124  * Checks if it's a space char. */
    125 #define KMK_CC_IS_SPACE_CH(a_ch)                    isspace((unsigned char)(a_ch))
    126 
    127123/** Aligns a size for the block allocator. */
    128124#define KMK_CC_BLOCK_ALIGN_SIZE(a_cb)               ( ((a_cb) + (sizeof(void *) - 1U)) & ~(uint32_t)(sizeof(void *) - 1U) )
     125
     126/** How to declare a no-return function.
     127 * Place between scope (if any) and return type.  */
     128#ifdef _MSC_VER
     129# define KMK_CC_FN_NO_RETURN                        declspec(noreturn)
     130#elif defined(__GNUC__)
     131# define KMK_CC_FN_NO_RETURN                        __attribute__((__noreturn__))
     132#endif
    129133
    130134
     
    177181 * All space characters, backslash (EOL escape), variable expansion dollar,
    178182 * variable assignment operator chars, recipe colon and recipe percent. */
    179 #define KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE       UINT16_C(8)
    180 #define KMK_CC_EVAL_IS_SPACE_OR_VAR_OR_RECIPE(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE)
     183#define KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE          UINT16_C(8)
     184#define KMK_CC_EVAL_IS_SPACE_VAR_OR_RECIPE(a_ch)    (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE)
     185/** Dollar character (possible variable expansion). */
     186#define KMK_CC_EVAL_CH_DOLLAR                       UINT16_C(16)
     187#define KMK_CC_EVAL_IS_DOLLAR(a_ch)                 (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_DOLLAR)
     188/** Dollar character (possible variable expansion). */
     189#define KMK_CC_EVAL_CH_BACKSLASH                    UINT16_C(32)
     190#define KMK_CC_EVAL_IS_BACKSLASH(a_ch)              (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_BACKSLASH)
    181191/** Possible EOL character. */
    182 #define KMK_CC_EVAL_CH_EOL_CANDIDATE                UINT16_C(16)
     192#define KMK_CC_EVAL_CH_EOL_CANDIDATE                UINT16_C(64)
    183193#define KMK_CC_EVAL_IS_EOL_CANDIDATE(a_ch)          (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_EOL_CANDIDATE)
    184194/** First character in a keyword. */
    185 #define KMK_CC_EVAL_CH_1ST_IN_KEYWORD               UINT16_C(32)
     195#define KMK_CC_EVAL_CH_1ST_IN_KEYWORD               UINT16_C(128)
    186196#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)
    187197/** Second character in a keyword. */
    188 #define KMK_CC_EVAL_CH_2ND_IN_KEYWORD               UINT16_C(64)
     198#define KMK_CC_EVAL_CH_2ND_IN_KEYWORD               UINT16_C(256)
    189199#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)
    190200/** First character in a variable qualifier keyword or 'define'. */
    191 #define KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD      UINT16_C(128)
     201#define KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD      UINT16_C(512)
    192202#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)
    193203/** Used when parsing variable names, looking for the end of a nested
    194204 *  variable reference.  Matches parentheses and backslash (escaped eol). */
    195 #define KMK_CC_EVAL_CH_PAREN_OR_SLASH               UINT16_C(256)
     205#define KMK_CC_EVAL_CH_PAREN_OR_SLASH               UINT16_C(1024)
    196206#define KMK_CC_EVAL_IS_PAREN_OR_SLASH(a_ch)         (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_PAREN_OR_SLASH)
    197207/** Used when parsing ifeq/ifneq (,) sequences.
    198208 * Matches parentheses, comma and dollar (for non-plain string detection). */
    199 #define KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR        UINT16_C(512)
     209#define KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR        UINT16_C(2048)
    200210#define KMK_CC_EVAL_IS_PAREN_COMMA_OR_DOLLAR(a_ch)  (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR)
     211
     212/** Test of space or dollar characters. */
     213#define KMK_CC_EVAL_IS_SPACE_OR_DOLLAR(a_ch)        (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & (KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_DOLLAR))
     214/** Test of space, dollar or backslash (possible EOL escape) characters. */
     215#define KMK_CC_EVAL_IS_SPACE_DOLLAR_OR_SLASH(a_ch)  (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & (KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_DOLLAR | KMK_CC_EVAL_CH_BACKSLASH))
     216/** Test of space, dollar, backslash (possible EOL escape) or variable
     217 * assingment characters. */
     218#define KMK_CC_EVAL_IS_SPACE_DOLLAR_SLASH_OR_ASSIGN(a_ch)   \
     219    (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & (KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE | KMK_CC_EVAL_CH_DOLLAR))
    201220/** @} */
    202221
     
    282301{
    283302    /** The instruction opcode number (KMKCCEXPINSTR). */
    284     KMKCCEXPINSTR           enmOpCode;
     303    KMKCCEXPINSTR           enmOpcode;
    285304} KMKCCEXPCORE;
    286305typedef KMKCCEXPCORE *PKMKCCEXPCORE;
     
    608627{
    609628    /** The instruction opcode number (KMKCCEVALINSTR). */
    610     KMKCCEVALINSTR          enmOpCode;
     629    KMKCCEVALINSTR          enmOpcode;
    611630    /** The line number in the source this statement is associated with. */
    612631    unsigned                iLine;
     
    636655    /** The core instruction. */
    637656    KMKCCEVALCORE           Core;
    638     /** Whether the 'export' directive was used. */
     657    /** Whether the 'export' qualifier was used. */
    639658    uint8_t                 fExport;
    640     /** Whether the 'override' directive was used. */
     659    /** Whether the 'override' qualifier was used. */
    641660    uint8_t                 fOverride;
    642     /** Whether the 'local' directive was used. */
     661    /** Whether the 'local' qualifier was used. */
    643662    uint8_t                 fLocal;
     663    /** Whether the 'private' qualifier was used. */
     664    uint8_t                 fPrivate;
    644665    /** The variable name.
    645666     * @remarks Plain text names are in variable_strcache. */
     
    10051026
    10061027
     1028/** This is parallel to KMKCCEVALINSTR.   */
     1029static const char * const g_apszEvalInstrNms[] =
     1030{
     1031    "jump",
     1032    "assign_recursive",
     1033    "assign_simple",
     1034    "assign_append",
     1035    "assign_prepend",
     1036    "assign_if_new",
     1037    "assign_define",
     1038    "export",
     1039    "unexport",
     1040    "export_all",
     1041    "unexport_all",
     1042    "ifdef_plain",
     1043    "ifndef_plain",
     1044    "ifdef_dynamic",
     1045    "ifndef_dynamic",
     1046    "ifeq",
     1047    "ifneq",
     1048    "if1of",
     1049    "ifn1of",
     1050    "if",
     1051    "include",
     1052    "include_silent",
     1053    "includedep",
     1054    "includedep_queue",
     1055    "includedep_flush",
     1056    "recipe_no_commands",
     1057    "recipe_start_normal",
     1058    "recipe_start_double_colon",
     1059    "recipe_start_pattern",
     1060    "recipe_commands",
     1061    "recipe_end",
     1062    "recipe_cancel_pattern",
     1063    "vpath",
     1064    "vpath_clear_pattern",
     1065    "vpath_clear_all",
     1066};
     1067
    10071068/*********************************************************************************************************************************
    10081069*   Internal Functions                                                                                                           *
     
    10291090
    10301091    /* space chars and zero terminator. */
    1031 #define MY_SPACE_BITS KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE
     1092#define MY_SPACE_BITS KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE
    10321093    KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ' ',  MY_SPACE_BITS);
    10331094    KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\t', MY_SPACE_BITS);
     
    10361097    KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\f', MY_SPACE_BITS);
    10371098    KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\r', MY_SPACE_BITS | KMK_CC_EVAL_CH_EOL_CANDIDATE);
    1038     KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
     1099    KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE);
    10391100#undef MY_SPACE_BITS
    10401101
     
    10571118
    10581119    /* Assignment punctuation and recipe stuff. */
    1059     KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '=', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
    1060     KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ':', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
    1061     KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '<', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
    1062     KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '?', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
    1063     KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '+', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
    1064     KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '%', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE); /* uncertain... */
     1120    KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '=', KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE);
     1121    KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ':', KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE);
    10651122
    10661123    /* For locating the end of variable expansion.  */
     
    10761133    KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ',', KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR);
    10771134    KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '$', KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR);
     1135
     1136    /* Misc. */
     1137    KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '$',  KMK_CC_EVAL_CH_DOLLAR);
     1138    KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_BACKSLASH);
     1139
     1140    /*
     1141     * Check that the eval instruction names match up.
     1142     */
     1143    KMK_CC_ASSERT(strcmp(g_apszEvalInstrNms[kKmkCcEvalInstr_ifneq], "ifneq") == 0);
     1144    KMK_CC_ASSERT(strcmp(g_apszEvalInstrNms[kKmkCcEvalInstr_vpath_clear_all], "vpath_clear_all") == 0);
    10781145}
    10791146
     
    14381505    /* Emit jump. */
    14391506    pJump = (PKMKCCEXPJUMP)((char *)pOldBlock + pOldBlock->offNext);
    1440     pJump->Core.enmOpCode = kKmkCcExpInstr_Jump;
     1507    pJump->Core.enmOpcode = kKmkCcExpInstr_Jump;
    14411508    pJump->pNext = pRet;
    14421509    pOldBlock->offNext += sizeof(*pJump);
     
    15081575    /* Emit jump. */
    15091576    pJump = (PKMKCCEVALJUMP)((char *)pOldBlock + pOldBlock->offNext);
    1510     pJump->Core.enmOpCode = kKmkCcEvalInstr_jump;
     1577    pJump->Core.enmOpcode = kKmkCcEvalInstr_jump;
    15111578    pJump->pNext = pRet;
    15121579    pOldBlock->offNext += sizeof(*pJump);
     
    15751642{
    15761643    PKMKCCEXPCORE pCore = kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pCore));
    1577     pCore->enmOpCode = kKmkCcExpInstr_Return;
     1644    pCore->enmOpcode = kKmkCcExpInstr_Return;
    15781645    kmk_cc_block_realign(ppBlockTail);
    15791646}
     
    16491716    uint32_t            cActualArgs = cArgs <= cMaxArgs || !cMaxArgs ? cArgs : cMaxArgs;
    16501717    PKMKCCEXPDYNFUNC    pInstr  = (PKMKCCEXPDYNFUNC)kmk_cc_block_alloc_exp(ppBlockTail, KMKCCEXPDYNFUNC_SIZE(cActualArgs));
    1651     pInstr->FnCore.Core.enmOpCode = kKmkCcExpInstr_DynamicFunction;
     1718    pInstr->FnCore.Core.enmOpcode = kKmkCcExpInstr_DynamicFunction;
    16521719    pInstr->FnCore.cArgs          = cActualArgs;
    16531720    pInstr->FnCore.pfnFunction    = pfnFunction;
     
    17501817    uint32_t            cActualArgs = cArgs <= cMaxArgs || !cMaxArgs ? cArgs : cMaxArgs;
    17511818    PKMKCCEXPPLAINFUNC  pInstr  = (PKMKCCEXPPLAINFUNC)kmk_cc_block_alloc_exp(ppBlockTail, KMKCCEXPPLAINFUNC_SIZE(cActualArgs));
    1752     pInstr->FnCore.Core.enmOpCode = kKmkCcExpInstr_PlainFunction;
     1819    pInstr->FnCore.Core.enmOpcode = kKmkCcExpInstr_PlainFunction;
    17531820    pInstr->FnCore.cArgs          = cActualArgs;
    17541821    pInstr->FnCore.pfnFunction    = pfnFunction;
     
    18211888
    18221889    pInstr = (PKMKCCEXPDYNVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
    1823     pInstr->Core.enmOpCode = kKmkCcExpInstr_DynamicVariable;
     1890    pInstr->Core.enmOpcode = kKmkCcExpInstr_DynamicVariable;
    18241891
    18251892    rc = kmk_cc_exp_compile_subprog(ppBlockTail, pchNameExpr, cchNameExpr, &pInstr->Subprog);
     
    18551922        {
    18561923            PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
    1857             pInstr->Core.enmOpCode = kKmkCcExpInstr_PlainVariable;
     1924            pInstr->Core.enmOpcode = kKmkCcExpInstr_PlainVariable;
    18581925            pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName);
    18591926        }
     
    18721939
    18731940            pInstr = (PKMKCCEXPSRPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
    1874             pInstr->Core.enmOpCode = kKmkCcExpInstr_SearchAndReplacePlainVariable;
     1941            pInstr->Core.enmOpcode = kKmkCcExpInstr_SearchAndReplacePlainVariable;
    18751942            pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName2);
    18761943
     
    19392006    {
    19402007        PKMKCCEXPCOPYSTRING pInstr = (PKMKCCEXPCOPYSTRING)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
    1941         pInstr->Core.enmOpCode = kKmkCcExpInstr_CopyString;
     2008        pInstr->Core.enmOpcode = kKmkCcExpInstr_CopyString;
    19422009        pInstr->cchCopy = cchStr;
    19432010        pInstr->pachSrc = pchStr;
     
    24022469    for (;;)
    24032470    {
    2404         switch (pInstrCore->enmOpCode)
     2471        switch (pInstrCore->enmOpcode)
    24052472        {
    24062473            case kKmkCcExpInstr_CopyString:
     
    26492716            default:
    26502717                fatal(NULL, _("Unknown string expansion opcode: %d (%#x)"),
    2651                       (int)pInstrCore->enmOpCode, (int)pInstrCore->enmOpCode);
     2718                      (int)pInstrCore->enmOpcode, (int)pInstrCore->enmOpcode);
    26522719                return NULL;
    26532720        }
     
    29062973{
    29072974    /** The token word (lexeme).   */
    2908     const char         *pszWord;
     2975    const char         *pchWord;
    29092976    /** The length of the word (lexeme). */
    29102977    uint32_t            cchWord;
     
    29132980} KMKCCEVALWORD;
    29142981typedef KMKCCEVALWORD *PKMKCCEVALWORD;
     2982typedef KMKCCEVALWORD const *PCKMKCCEVALWORD;
    29152983
    29162984
     
    30663134}
    30673135
    3068 static void kmk_cc_eval_fatal(PKMKCCEVALCOMPILER pCompiler, const char *pchWhere, const char *pszMsg, ...)
     3136static void KMK_CC_FN_NO_RETURN kmk_cc_eval_fatal(PKMKCCEVALCOMPILER pCompiler, const char *pchWhere, const char *pszMsg, ...)
    30693137{
    30703138    va_list  va;
     
    31173185
    31183186
    3119 static void kmk_cc_eval_fatal_eol(PKMKCCEVALCOMPILER pCompiler, const char *pchEol, unsigned iLine, size_t offLine)
     3187static KMK_CC_FN_NO_RETURN void
     3188kmk_cc_eval_fatal_eol(PKMKCCEVALCOMPILER pCompiler, const char *pchEol, unsigned iLine, size_t offLine)
    31203189{
    31213190    pCompiler->iLine   = iLine;
     
    31253194        kmk_cc_eval_fatal(pCompiler, pchEol, "Missing 2nd EOL character: found %#x instead of %#x\n",
    31263195                                   pchEol, pCompiler->chSecondEol);
     3196}
     3197
     3198
     3199static void kmk_cc_eval_warn(PKMKCCEVALCOMPILER pCompiler, const char *pchWhere, const char *pszMsg, ...)
     3200{
     3201    /** @todo warnings.   */
     3202    (void)pchWhere;
     3203    (void)pCompiler;
     3204    (void)pszMsg;
    31273205}
    31283206
     
    31553233 * @param   fPlain      Whether it's plain or not.  If not, we'll compile it.
    31563234 */
    3157 static void kmk_cc_eval_do_subprogram_or_plain(PKMKCCEVALCOMPILER pCompiler, PKMKCCEXPSUBPROGORPLAIN pOperand,
    3158                                                const char *pszString, size_t cchString, int fPlain)
     3235static void kmk_cc_eval_init_subprogram_or_plain(PKMKCCEVALCOMPILER pCompiler, PKMKCCEXPSUBPROGORPLAIN pOperand,
     3236                                                 const char *pszString, size_t cchString, int fPlain)
    31593237{
    31603238    pOperand->fPlainIsInVarStrCache  = 0;
     
    31693247    else
    31703248        kmk_cc_eval_compile_string_exp_subprog(pCompiler, pszString, cchString, &pOperand->u.Subprog);
     3249}
     3250
     3251/**
     3252 * Initializes an array of subprogram-or-plain (spp) operands from a word array.
     3253 *
     3254 * The words will be duplicated and the caller must therefore call
     3255 * kmk_cc_block_realign() when done (it's not done here as the caller may
     3256 * initialize several string operands and we don't want any unnecessary
     3257 * fragmentation).
     3258 *
     3259 * @param   pCompiler   The compiler state.
     3260 * @param   cWords      The number of words to copy.
     3261 * @param   paSrc       The source words.
     3262 * @param   paDst       The destination subprogram-or-plain array.
     3263 */
     3264static void kmk_cc_eval_init_spp_array_from_duplicated_words(PKMKCCEVALCOMPILER pCompiler, unsigned cWords,
     3265                                                             PKMKCCEVALWORD paSrc, PKMKCCEXPSUBPROGORPLAIN paDst)
     3266{
     3267    unsigned i;
     3268    for (i = 0; i < cWords; i++)
     3269    {
     3270        const char *pszCopy = kmk_cc_block_strdup(pCompiler->ppBlockTail, paSrc[i].pchWord, paSrc[i].cchWord);
     3271        paDst[i].fPlainIsInVarStrCache  = 0;
     3272        paDst[i].bUser                  = 0;
     3273        paDst[i].bUser2                 = 0;
     3274        if (paSrc[i].enmToken == kKmkCcEvalToken_WordWithDollar)
     3275        {
     3276            paDst[i].fSubprog    = 1;
     3277            kmk_cc_eval_compile_string_exp_subprog(pCompiler, pszCopy, paSrc[i].cchWord, &paDst[i].u.Subprog);
     3278        }
     3279        else
     3280        {
     3281            paDst[i].fSubprog    = 0;
     3282            paDst[i].u.Plain.cch = paSrc[i].cchWord;
     3283            paDst[i].u.Plain.psz = pszCopy;
     3284        }
     3285        KMK_CC_EVAL_DPRINTF(("  %s\n", pszCopy));
     3286    }
    31713287}
    31723288
     
    33103426     || ((a_ch) == '\\' && (a_ch2) == (a_pCompiler)->chFirstEol) )
    33113427
     3428
     3429/**
     3430 * Common path for space skipping worker functions when escaped EOLs may be
     3431 * involed.
     3432 *
     3433 * @returns Points to the first non-space character or end of input.
     3434 * @param   pchWord         The current position. There is some kind of char
     3435 * @param   cchLeft         The current number of chars left to parse in the
     3436 *                          current line.
     3437 * @param   pcchLeft        Where to store the updated @a cchLeft value.
     3438 * @param   pCompiler       The compiler instance data.
     3439 */
     3440static const char *kmk_cc_eval_skip_spaces_with_esc_eol(const char *pchWord, size_t cchLeft, size_t *pcchLeft,
     3441                                                        PKMKCCEVALCOMPILER pCompiler)
     3442{
     3443    /*
     3444     * Skip further spaces. We unrolls 4 loops here.
     3445     * ASSUMES cchEscEolSeq is either 2 or 3!
     3446     */
     3447    KMK_CC_ASSERT(pCompiler->cchEscEolSeq == 2 || pCompiler->cchEscEolSeq == 3);
     3448    KMK_CC_ASSERT(pCompiler->iEscEol < pCompiler->cEscEols);
     3449    while (cchLeft >= 4)
     3450    {
     3451        /* First char. */
     3452        char ch = pchWord[0];
     3453        if (KMK_CC_EVAL_IS_SPACE(ch))
     3454        { /* maybe likely */ }
     3455        else if (   ch == '\\'
     3456                 && pchWord[1] == pCompiler->chFirstEol)
     3457        {
     3458            pchWord += pCompiler->cchEscEolSeq;
     3459            cchLeft -= pCompiler->cchEscEolSeq;
     3460            pCompiler->iEscEol++;
     3461            continue;
     3462        }
     3463        else
     3464        {
     3465            *pcchLeft = cchLeft;
     3466            return pchWord;
     3467        }
     3468
     3469        /* Second char. */
     3470        ch = pchWord[1];
     3471        if (KMK_CC_EVAL_IS_SPACE(ch))
     3472        { /* maybe likely */ }
     3473        else if (   ch == '\\'
     3474                 && pchWord[2] == pCompiler->chFirstEol)
     3475        {
     3476            pchWord += 1 + pCompiler->cchEscEolSeq;
     3477            cchLeft -= 1 + pCompiler->cchEscEolSeq;
     3478            pCompiler->iEscEol++;
     3479            continue;
     3480        }
     3481        else
     3482        {
     3483            *pcchLeft = cchLeft - 1;
     3484            return pchWord + 1;
     3485        }
     3486
     3487        /* Third char. */
     3488        ch = pchWord[2];
     3489        if (KMK_CC_EVAL_IS_SPACE(ch))
     3490        { /* maybe likely */ }
     3491        else if (   ch == '\\'
     3492                 && pchWord[3] == pCompiler->chFirstEol
     3493                 && cchLeft >= 2 + pCompiler->cchEscEolSeq)
     3494        {
     3495            pchWord += 2 + pCompiler->cchEscEolSeq;
     3496            cchLeft -= 2 + pCompiler->cchEscEolSeq;
     3497            pCompiler->iEscEol++;
     3498            continue;
     3499        }
     3500        else
     3501        {
     3502            *pcchLeft = cchLeft - 2;
     3503            return pchWord + 2;
     3504        }
     3505
     3506        /* Third char. */
     3507        ch = pchWord[3];
     3508        if (KMK_CC_EVAL_IS_SPACE(ch))
     3509        {
     3510            pchWord += 4;
     3511            cchLeft -= 4;
     3512        }
     3513        else if (   ch == '\\'
     3514                 && cchLeft >= 3 + pCompiler->cchEscEolSeq
     3515                 && pchWord[4] == pCompiler->chFirstEol)
     3516        {
     3517            pchWord += 3 + pCompiler->cchEscEolSeq;
     3518            cchLeft -= 3 + pCompiler->cchEscEolSeq;
     3519            pCompiler->iEscEol++;
     3520        }
     3521        else
     3522        {
     3523            *pcchLeft = cchLeft - 3;
     3524            return pchWord + 3;
     3525        }
     3526    }
     3527
     3528    /*
     3529     * Simple loop for the final three chars.
     3530     */
     3531    while (cchLeft > 0)
     3532    {
     3533        /* First char. */
     3534        char ch = *pchWord;
     3535        if (KMK_CC_EVAL_IS_SPACE(ch))
     3536        {
     3537            pchWord += 1;
     3538            cchLeft -= 1;
     3539        }
     3540        else if (   ch == '\\'
     3541                 && cchLeft > pCompiler->cchEolSeq
     3542                 && pchWord[1] == pCompiler->chFirstEol)
     3543        {
     3544            pchWord += pCompiler->cchEscEolSeq;
     3545            cchLeft -= pCompiler->cchEscEolSeq;
     3546            pCompiler->iEscEol++;
     3547        }
     3548        else
     3549            break;
     3550    }
     3551
     3552    *pcchLeft = cchLeft;
     3553    return pchWord;
     3554}
     3555
     3556
     3557/**
     3558 * Common path for space skipping worker functions when no escaped EOLs need
     3559 * considering.
     3560 *
     3561 * @returns Points to the first non-space character or end of input.
     3562 * @param   pchWord         The current position. There is some kind of char
     3563 * @param   cchLeft         The current number of chars left to parse in the
     3564 *                          current line.
     3565 * @param   pcchLeft        Where to store the updated @a cchLeft value.
     3566 * @param   pCompiler       The compiler instance data.
     3567 */
     3568static const char *kmk_cc_eval_skip_spaces_without_esc_eol(const char *pchWord, size_t cchLeft, size_t *pcchLeft,
     3569                                                           PKMKCCEVALCOMPILER pCompiler)
     3570{
     3571    /*
     3572     * 4x loop unroll.
     3573     */
     3574    while (cchLeft >= 4)
     3575    {
     3576        if (KMK_CC_EVAL_IS_SPACE(pchWord[0]))
     3577        {
     3578            if (KMK_CC_EVAL_IS_SPACE(pchWord[1]))
     3579            {
     3580                if (KMK_CC_EVAL_IS_SPACE(pchWord[2]))
     3581                {
     3582                    if (KMK_CC_EVAL_IS_SPACE(pchWord[3]))
     3583                    {
     3584                        pchWord += 4;
     3585                        cchLeft -= 4;
     3586                    }
     3587                    else
     3588                    {
     3589                        *pcchLeft = cchLeft - 3;
     3590                        return pchWord + 3;
     3591                    }
     3592                }
     3593                else
     3594                {
     3595                    *pcchLeft = cchLeft - 2;
     3596                    return pchWord + 2;
     3597                }
     3598            }
     3599            else
     3600            {
     3601                *pcchLeft = cchLeft - 1;
     3602                return pchWord + 1;
     3603            }
     3604        }
     3605        else
     3606        {
     3607            *pcchLeft = cchLeft;
     3608            return pchWord;
     3609        }
     3610    }
     3611
     3612    /*
     3613     * The last 3. Not entirely sure if this yield good code.
     3614     */
     3615    switch (cchLeft & 3)
     3616    {
     3617        case 3:
     3618            if (!KMK_CC_EVAL_IS_SPACE(*pchWord))
     3619                break;
     3620            pchWord++;
     3621            cchLeft--;
     3622        case 2:
     3623            if (!KMK_CC_EVAL_IS_SPACE(*pchWord))
     3624                break;
     3625            pchWord++;
     3626            cchLeft--;
     3627        case 1:
     3628            if (!KMK_CC_EVAL_IS_SPACE(*pchWord))
     3629                break;
     3630            pchWord++;
     3631            cchLeft--;
     3632        case 0:
     3633            break;
     3634    }
     3635
     3636    *pcchLeft = cchLeft;
     3637    return pchWord;
     3638}
     3639
     3640
    33123641/**
    33133642 * Used to skip spaces after a word.
     
    33493678    } while (0)
    33503679
    3351 
    3352 //static int kmk_cc_eval_skip_esc_eol_slow(const char *pchWord, size_t cchLeft, PKMKCCEVALCOMPILER pCompiler,
    3353 //                                                  const char **ppchWord, size_t *pcchLeft)
    3354 //{
    3355 //    KMK_CC_ASSERT(pchWord[0] == '\\');
    3356 //    if (pCompiler->cEscEols)
    3357 //    {
    3358 //        size_t cchMin = 1 + pCompiler->chFirstEol;
    3359 //        if (cchLeft >= cchMin)
    3360 //        {
    3361 //            /* The simple case, no extra backslashes. */
    3362 //            if (pchWord[1] == pCompiler->chFirstEol)
    3363 //            {
    3364 //                *pcchLeft  = cchLeft - cchMin;
    3365 //                *pchWord   = pchWord + cchMin;
    3366 //                return 1;
    3367 //            }
    3368 //
    3369 //            /* The unlikly case,  */
    3370 //
    3371 //        }
    3372 //    }
    3373 //    return 0;
    3374 //}
    3375 
    3376 
    33773680/**
    33783681 * The slow path of KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD.
     
    33943697 */
    33953698static const char *kmk_cc_eval_skip_spaces_after_word_slow(const char *pchWord, size_t *pcchLeft, char ch,
    3396                                                                     PKMKCCEVALCOMPILER pCompiler)
     3699                                                           PKMKCCEVALCOMPILER pCompiler)
    33973700{
    33983701    size_t cchLeft = *pcchLeft;
     3702
     3703    /*
     3704     * It's all very simple when we don't have to consider escaped EOLs.
     3705     */
     3706    if (pCompiler->iEscEol >= pCompiler->cEscEols)
     3707    {
     3708        if (ch != '\\')
     3709        {
     3710            pchWord += 1;
     3711            cchLeft -= 1;
     3712        }
     3713        else
     3714            return pchWord;
     3715        return kmk_cc_eval_skip_spaces_without_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler);
     3716    }
    33993717
    34003718    /*
     
    34203738        cchLeft -= pCompiler->cchEscEolSeq;
    34213739        pCompiler->iEscEol++;
     3740
     3741        if (pCompiler->iEscEol < pCompiler->cEscEols)
     3742        { /* likely */ }
     3743        else return kmk_cc_eval_skip_spaces_without_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler);
    34223744    }
    34233745    else
    34243746        return pchWord;
    3425 
    3426     /*
    3427      * Skip further spaces. We unrolls 4 loops here.
    3428      * ASSUMES cchEscEolSeq is either 2 or 3!
    3429      */
    3430     KMK_CC_ASSERT(pCompiler->cchEscEolSeq == 2 || pCompiler->cchEscEolSeq == 3);
    3431     while (cchLeft >= 4)
    3432     {
    3433         /* First char. */
    3434         ch = pchWord[0];
    3435         if (KMK_CC_EVAL_IS_SPACE(ch))
    3436         { /* maybe likely */ }
    3437         else if (   ch == '\\'
    3438                  && pchWord[1] == pCompiler->chFirstEol)
    3439         {
    3440             pchWord += pCompiler->cchEscEolSeq;
    3441             cchLeft -= pCompiler->cchEscEolSeq;
    3442             pCompiler->iEscEol++;
    3443             continue;
    3444         }
    3445         else
    3446         {
    3447             *pcchLeft = cchLeft;
    3448             return pchWord;
    3449         }
    3450 
    3451         /* Second char. */
    3452         ch = pchWord[1];
    3453         if (KMK_CC_EVAL_IS_SPACE(ch))
    3454         { /* maybe likely */ }
    3455         else if (   ch == '\\'
    3456                  && pchWord[2] == pCompiler->chFirstEol)
    3457         {
    3458             pchWord += 1 + pCompiler->cchEscEolSeq;
    3459             cchLeft -= 1 + pCompiler->cchEscEolSeq;
    3460             pCompiler->iEscEol++;
    3461             continue;
    3462         }
    3463         else
    3464         {
    3465             *pcchLeft = cchLeft - 1;
    3466             return pchWord + 1;
    3467         }
    3468 
    3469         /* Third char. */
    3470         ch = pchWord[2];
    3471         if (KMK_CC_EVAL_IS_SPACE(ch))
    3472         { /* maybe likely */ }
    3473         else if (   ch == '\\'
    3474                  && pchWord[3] == pCompiler->chFirstEol
    3475                  && cchLeft >= 2 + pCompiler->cchEscEolSeq)
    3476         {
    3477             pchWord += 2 + pCompiler->cchEscEolSeq;
    3478             cchLeft -= 2 + pCompiler->cchEscEolSeq;
    3479             pCompiler->iEscEol++;
    3480             continue;
    3481         }
    3482         else
    3483         {
    3484             *pcchLeft = cchLeft - 2;
    3485             return pchWord + 2;
    3486         }
    3487 
    3488         /* Third char. */
    3489         ch = pchWord[3];
    3490         if (KMK_CC_EVAL_IS_SPACE(ch))
    3491         {
    3492             pchWord += 4;
    3493             cchLeft -= 4;
    3494         }
    3495         else if (   ch == '\\'
    3496                  && cchLeft >= 3 + pCompiler->cchEscEolSeq
    3497                  && pchWord[4] == pCompiler->chFirstEol)
    3498         {
    3499             pchWord += 3 + pCompiler->cchEscEolSeq;
    3500             cchLeft -= 3 + pCompiler->cchEscEolSeq;
    3501             pCompiler->iEscEol++;
    3502         }
    3503         else
    3504         {
    3505             *pcchLeft = cchLeft - 3;
    3506             return pchWord + 3;
    3507         }
    3508     }
    3509 
    3510     /*
    3511      * Simple loop for the final three chars.
    3512      */
    3513     while (cchLeft > 0)
    3514     {
    3515         /* First char. */
    3516         ch = *pchWord;
    3517         if (KMK_CC_EVAL_IS_SPACE(ch))
    3518         {
    3519             pchWord += 1;
    3520             cchLeft -= 1;
    3521         }
    3522         else if (   ch == '\\'
    3523                  && cchLeft > pCompiler->cchEolSeq
    3524                  && pchWord[1] == pCompiler->chFirstEol)
    3525         {
    3526             pchWord += pCompiler->cchEscEolSeq;
    3527             cchLeft -= pCompiler->cchEscEolSeq;
    3528             pCompiler->iEscEol++;
    3529         }
    3530         else
    3531             break;
    3532     }
    3533 
    3534     *pcchLeft = cchLeft;
    3535     return pchWord;
    3536 }
    3537 
    3538 
    3539 #if 0
    3540 /**
    3541  * Used to shed trailing spaces in a string by decrementing @ a_cchLeft.
    3542  *
    3543  * @param   a_pCompiler     The compiler instance data.
    3544  * @param   a_pchWord       The current input position, this will not be
    3545  *                          changed.
    3546  * @param   a_cchLeft       The number of chars left to parse.  This will be
    3547  *                          updated if there are trailing spaces.
    3548  */
    3549 #define KMK_CC_EVAL_SHED_TRAILING_SPACES(a_pCompiler, a_pchWord, a_cchLeft) \
     3747    return kmk_cc_eval_skip_spaces_with_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler);
     3748}
     3749
     3750
     3751/**
     3752 * Skip zero or more spaces.
     3753 *
     3754 * This macro deals with a single space, if there are more or we're hittin some
     3755 * possible escaped EOL sequence, work is deferred to a worker function.
     3756 *
     3757 * @param   a_pCompiler The compiler state.
     3758 * @param   a_pchWord   The current input position. Advanced past spaces.
     3759 * @param   a_cchLeft   The amount of input left to parse. Will be updated.
     3760 */
     3761#define KMK_CC_EVAL_SKIP_SPACES(a_pCompiler, a_pchWord, a_cchLeft) \
    35503762    do { \
    35513763        if ((a_cchLeft) > 0) \
    35523764        { \
    3553             char const chShedTrailing1 = (a_pchWord)[(a_cchLeft) - 1]; \
    3554             if (KMK_CC_EVAL_IS_SPACE(chShedTrailing1)) \
     3765            char chSkipSpaces = *(a_pchWord); \
     3766            if (KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(chSkipSpaces)) \
    35553767            { \
    3556                 /* If there are two or more, or any of these are potential EOL chars, call worker. */ \
    3557                 if (!KMK_CC_EVAL_IS_EOL_CANDIDATE(chShedTrailing1)) \
     3768                if (chSkipSpaces != '\\') \
    35583769                { \
     3770                    (a_pchWord) += 1; \
    35593771                    (a_cchLeft) -= 1; \
    3560                     if ((a_cchLeft) > 0) \
    3561                     { \
    3562                         char const chShedTrailing2 = (a_pchWord)[(a_cchLeft) - 1]; \
    3563                         if (KMK_CC_EVAL_IS_SPACE(chShedTrailing)) \
    3564                             (a_cchLeft) = kmk_cc_eval_shed_trailing_spaces_slow(a_pchWord, (a_cchLeft), \
    3565                                                                                          chShedTrailing2, a_pCompiler); \
    3566                     } \
     3772                    chSkipSpaces = *(a_pchWord); \
     3773                    if (KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(chSkipSpaces)) \
     3774                        (a_pchWord) = kmk_cc_eval_skip_spaces_slow(a_pchWord, &(a_cchLeft), chSkipSpaces, a_pCompiler); \
    35673775                } \
    35683776                else \
    3569                     (a_cchWord) = kmk_cc_eval_shed_trailing_spaces_slow(a_pchWord, (a_cchLeft), \
    3570                                                                                  chShedTrailing1, a_pCompiler); \
     3777                    (a_pchWord) = kmk_cc_eval_skip_spaces_slow(a_pchWord, &(a_cchLeft), chSkipSpaces, a_pCompiler); \
    35713778            } \
    35723779        } \
     
    35743781
    35753782
    3576 
    3577 /**
    3578  * The slow path of KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD.
    3579  *
    3580  * It's called when a space or backslash is encountered as the 2nd character.
    3581  * A second space is likely to be followed by more spaces, while an escaped
    3582  * newline (if it checks out) is very likely to be followed by more spaces or
    3583  * tabs before we get to anything worthwhile.  Also, checking for an esacped
    3584  * end-of-line character is a bit tedious. (It could be worse, though, as we
    3585  * know that any EOL sequence inside the text area we're currently working on
    3586  * must be escaped.)
     3783/**
     3784 * Worker for KMK_CC_EVAL_SKIP_SPACES.
    35873785 *
    35883786 * @returns Points to the first non-space character or end of input.
    35893787 * @param   pchWord             The current position. There is some kind of char
    3590  * @param   cchLeft             The number of chars left to parse at @a pchWord.
    3591  * @param   ch                  The current tail character.
     3788 * @param   pcchLeft            Pointer to the cchLeft variable, this is both
     3789 *                              input and output.
     3790 * @param   ch                  The current character.
    35923791 * @param   pCompiler           The compiler instance data.
    35933792 */
    3594 static size_t kmk_cc_eval_shed_trailing_spaces_slow(const char *pchWord, size_t cchLeft, char ch,
    3595                                                     PKMKCCEVALCOMPILER pCompiler)
    3596 {
    3597     for (;;)
    3598     {
    3599         if (KMK_CC_EVAL_IS_EOL_CANDIDATE(chShedTrailing1))
    3600         {
    3601 
     3793static const char *kmk_cc_eval_skip_spaces_slow(const char *pchWord, size_t *pcchLeft, char ch, PKMKCCEVALCOMPILER pCompiler)
     3794{
     3795    size_t cchLeft = *pcchLeft;
     3796#ifdef KMK_CC_STRICT
     3797    size_t offWordCcStrict = pchWord - pCompiler->pszContent;
     3798#endif
     3799    KMK_CC_ASSERT(cchLeft > 0);
     3800    KMK_CC_ASSERT(cchLeft <= pCompiler->cchLine);
     3801    KMK_CC_ASSERT(*pchWord == ch);
     3802    KMK_CC_ASSERT(KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(ch));
     3803    KMK_CC_ASSERT(offWordCcStrict >= pCompiler->offLine);
     3804    KMK_CC_ASSERT(offWordCcStrict < pCompiler->offLine + pCompiler->cchLine);
     3805    KMK_CC_ASSERT(   pCompiler->iEscEol >= pCompiler->cEscEols
     3806                  || offWordCcStrict <= pCompiler->paEscEols[pCompiler->iEscEol].offEsc);
     3807    KMK_CC_ASSERT(   pCompiler->iEscEol >= pCompiler->cEscEols
     3808                  || pCompiler->iEscEol == 0
     3809                  || offWordCcStrict >= pCompiler->paEscEols[pCompiler->iEscEol - 1].offEol + pCompiler->cchEolSeq);
     3810
     3811    /*
     3812     * If we don't need to consider escaped EOLs, things are much much simpler.
     3813     */
     3814    if (pCompiler->iEscEol >= pCompiler->cEscEols)
     3815    {
     3816        if (ch != '\\')
     3817        {
     3818            pchWord++;
     3819            cchLeft--;
    36023820        }
    3603 
    3604     }
    3605 }
    3606 #endif
     3821        else
     3822            return pchWord;
     3823        return kmk_cc_eval_skip_spaces_without_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler);
     3824    }
     3825
     3826    /*
     3827     * Possible escaped EOL complications.
     3828     */
     3829    if (ch != '\\')
     3830    {
     3831        pchWord++;
     3832        cchLeft--;
     3833    }
     3834    else
     3835    {
     3836        size_t          cchSkip;
     3837        size_t          offWord;
     3838        unsigned        iEscEol = pCompiler->iEscEol;
     3839        if (iEscEol >= pCompiler->cEscEols)
     3840            return pchWord;
     3841
     3842        offWord = pchWord - pCompiler->pszContent;
     3843        if (offWord < pCompiler->paEscEols[iEscEol].offEsc)
     3844            return pchWord;
     3845        KMK_CC_ASSERT(offWord == pCompiler->paEscEols[iEscEol].offEsc);
     3846
     3847        cchSkip  = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq - offWord;
     3848        pchWord += cchSkip;
     3849        cchLeft -= cchSkip;
     3850        pCompiler->iEscEol = ++iEscEol;
     3851
     3852        if (iEscEol < pCompiler->cEscEols)
     3853        { /* likely */ }
     3854        else return kmk_cc_eval_skip_spaces_without_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler);
     3855    }
     3856    return kmk_cc_eval_skip_spaces_with_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler);
     3857}
    36073858
    36083859
     
    36473898    {
    36483899        char ch = pszContent[off];
    3649         if (!KMK_CC_EVAL_IS_SPACE_OR_VAR_OR_RECIPE(ch))
     3900        if (!KMK_CC_EVAL_IS_SPACE_DOLLAR_OR_SLASH(ch))
     3901            off++;
     3902        else if (KMK_CC_EVAL_IS_SPACE(ch))
     3903            break;
     3904        else if (ch == '$')
     3905        {
     3906            off++;
     3907            if (off < offLineEnd)
     3908            {
     3909                char const chOpen = pszContent[off];
     3910                if (chOpen == '(' || chOpen == '{')
     3911                {
     3912                    /*
     3913                     * Got a $(VAR) or ${VAR} to deal with here.  This may
     3914                     * include nested variable references and span multiple
     3915                     * lines (at least for function calls).
     3916                     *
     3917                     * We scan forward till we've found the corresponding
     3918                     * closing parenthesis, considering any open parentheses
     3919                     * of the same kind as worth counting, even if there are
     3920                     * no dollar preceeding them, just like GNU make does.
     3921                     */
     3922                    size_t const offStart = off - 1;
     3923                    char const   chClose  = chOpen == '(' ? ')' : '}';
     3924                    unsigned     cOpen    = 1;
     3925                    off++;
     3926                    for (;;)
     3927                    {
     3928                        if (off < offLineEnd)
     3929                        {
     3930                            ch = pszContent[off];
     3931                            if (!(KMK_CC_EVAL_IS_PAREN_OR_SLASH(ch)))
     3932                                off++;
     3933                            else
     3934                            {
     3935                                off++;
     3936                                if (ch == chClose)
     3937                                {
     3938                                    if (--cOpen == 0)
     3939                                        break;
     3940                                }
     3941                                else if (ch == chOpen)
     3942                                    cOpen++;
     3943                                else if (   ch == '\\'
     3944                                         && iEscEol < pCompiler->cEscEols
     3945                                         && off == pCompiler->paEscEols[iEscEol].offEsc)
     3946                                {
     3947                                    off = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq;
     3948                                    pCompiler->iEscEol = ++iEscEol;
     3949                                }
     3950                            }
     3951                        }
     3952                        else if (cOpen == 1)
     3953                            kmk_cc_eval_fatal(pCompiler, &pszContent[offStart],
     3954                                              "Variable reference is missing '%c'", chClose);
     3955                        else
     3956                            kmk_cc_eval_fatal(pCompiler, &pszContent[offStart],
     3957                                              "%u variable references are missing '%c'", cOpen, chClose);
     3958                    }
     3959                }
     3960                /* Single char variable name. */
     3961                else if (!KMK_CC_EVAL_IS_SPACE(chOpen))
     3962                {  /* likely */ }
     3963                else
     3964                    kmk_cc_eval_fatal(pCompiler, &pszContent[off], "Expected variable name after '$', not end of line");
     3965            }
     3966            else
     3967                kmk_cc_eval_fatal(pCompiler, &pszContent[off], "Expected variable name after '$', not end of line");
     3968            fPlain = 0;
     3969        }
     3970        /* Deal with potential escaped EOL. */
     3971        else if (   ch != '\\'
     3972                 || iEscEol >= pCompiler->cEscEols
     3973                 || off != pCompiler->paEscEols[iEscEol].offEsc )
    36503974            off++;
    36513975        else
    3652         {
    3653             if (KMK_CC_EVAL_IS_SPACE(ch))
    3654                 break;
    3655 
    3656             if (ch == '$')
    3657             {
    3658                 off++;
    3659                 if (off < offLineEnd)
    3660                 {
    3661                     char const chOpen = pszContent[off];
    3662                     if (chOpen == '(' || chOpen == '{')
    3663                     {
    3664                         /*
    3665                          * Got a $(VAR) or ${VAR} to deal with here.  This may
    3666                          * include nested variable references and span multiple
    3667                          * lines (at least for function calls).
    3668                          *
    3669                          * We scan forward till we've found the corresponding
    3670                          * closing parenthesis, considering any open parentheses
    3671                          * of the same kind as worth counting, even if there are
    3672                          * no dollar preceeding them, just like GNU make does.
    3673                          */
    3674                         size_t const offStart = off - 1;
    3675                         char const   chClose  = chOpen == '(' ? ')' : '}';
    3676                         unsigned     cOpen    = 1;
    3677                         for (;;)
    3678                         {
    3679                             if (off < offLineEnd)
    3680                             {
    3681                                 ch = pszContent[off];
    3682                                 if (!(KMK_CC_EVAL_IS_PAREN_OR_SLASH(ch)))
    3683                                     off++;
    3684                                 else
    3685                                 {
    3686                                     off++;
    3687                                     if (ch == chClose)
    3688                                     {
    3689                                         if (--cOpen == 0)
    3690                                             break;
    3691                                     }
    3692                                     else if (ch == chOpen)
    3693                                         cOpen++;
    3694                                     else if (   ch == '\\'
    3695                                              && iEscEol < pCompiler->cEscEols
    3696                                              && off == pCompiler->paEscEols[iEscEol].offEsc)
    3697                                     {
    3698                                         off = pCompiler->paEscEols[iEscEol].offEsc + pCompiler->cchEolSeq;
    3699                                         iEscEol++;
    3700                                         pCompiler->iEscEol = iEscEol;
    3701                                     }
    3702                                 }
    3703                             }
    3704                             else if (cOpen == 1)
    3705                                 kmk_cc_eval_fatal(pCompiler, &pszContent[offStart],
    3706                                                   "Variable reference is missing '%c'", chClose);
    3707                             else
    3708                                 kmk_cc_eval_fatal(pCompiler, &pszContent[offStart],
    3709                                                   "%u variable references are missing '%c'", cOpen, chClose);
    3710                         }
    3711                     }
    3712                     /* Single char variable name. */
    3713                     else if (!KMK_CC_EVAL_IS_SPACE(chOpen))
    3714                     {  /* likely */ }
    3715                     else
    3716                         kmk_cc_eval_fatal(pCompiler, &pszContent[off], "Expected variable name after '$', not end of line");
    3717                 }
    3718                 else
    3719                     kmk_cc_eval_fatal(pCompiler, &pszContent[off], "Expected variable name after '$', not end of line");
    3720                 fPlain = 0;
    3721             }
    3722             /* Deal with potential escaped EOL. */
    3723             else if (   ch != '\\'
    3724                      || iEscEol >= pCompiler->cEscEols
    3725                      || off != pCompiler->paEscEols[iEscEol].offEsc )
    3726                 off++;
    3727             else
    3728                 break;
    3729         }
     3976            break;
    37303977    }
    37313978
     
    38584105}
    38594106#endif /* unused atm */
     4107
     4108
     4109/**
     4110 * Helper for ensuring that we've got sufficient number of words allocated.
     4111 */
     4112#define KMK_CC_EVAL_ENSURE_WORDS(a_pCompiler, a_cRequiredWords) \
     4113    do { \
     4114        if ((a_cRequiredWords) < (a_pCompiler)->cWordsAllocated) \
     4115        { /* likely */ } \
     4116        else \
     4117        { \
     4118            unsigned cEnsureWords = ((a_cRequiredWords) + 3 /*15*/) & ~(unsigned)3/*15*/; \
     4119            KMK_CC_ASSERT((a_cRequiredWords) < 0x8000); \
     4120            (a_pCompiler)->paWords = (PKMKCCEVALWORD)xmalloc(cEnsureWords * sizeof((a_pCompiler)->paWords)[0]); \
     4121        } \
     4122    } while (0)
     4123
     4124/**
     4125 * Parses the remainder of the line into simple words.
     4126 *
     4127 * The resulting words are classified as either kKmkCcEvalToken_WordPlain or
     4128 * kKmkCcEvalToken_WordWithDollar.
     4129 *
     4130 * @returns Number of words.
     4131 * @param   pCompiler   The compiler state.
     4132 * @param   pchWord     Where to start, we expect this to be at a word.
     4133 * @param   cchLeft     The number of chars left to parse on this line.
     4134 *                      This is expected to be non-zero.
     4135 */
     4136static unsigned kmk_cc_eval_parse_words(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
     4137{
     4138    unsigned iEscEol  = pCompiler->iEscEol;
     4139    unsigned cEscEols = pCompiler->cEscEols;
     4140    unsigned cWords   = 0;
     4141
     4142    /* Precoditions. */
     4143    KMK_CC_ASSERT(cchLeft > 0);
     4144    KMK_CC_ASSERT(!KMK_CC_EVAL_IS_SPACE(*pchWord));
     4145
     4146    /*
     4147     * If we don't have to deal with escaped EOLs, the find-end-of word search
     4148     * becomes a little bit simpler.  Since this function will be used a lot
     4149     * for simple lines with single words, this could maybe save a nano second
     4150     * or two.
     4151     */
     4152    if (iEscEol >= cEscEols)
     4153    {
     4154        do
     4155        {
     4156            size_t          cchSkipAfter = 0;
     4157            size_t          cchWord      = 1;
     4158            KMKCCEVALTOKEN  enmToken     = kKmkCcEvalToken_WordPlain;
     4159
     4160            /* Find the end of the current word. */
     4161            while (cchWord < cchLeft)
     4162            {
     4163                char ch = pchWord[cchWord];
     4164                if (!KMK_CC_EVAL_IS_SPACE_OR_DOLLAR(ch))
     4165                { /* likely */ }
     4166                else if (ch == '$')
     4167                    enmToken = kKmkCcEvalToken_WordWithDollar;
     4168                else
     4169                    break;
     4170                cchWord++;
     4171            }
     4172
     4173            /* Add the word. */
     4174            KMK_CC_EVAL_ENSURE_WORDS(pCompiler, cWords + 1);
     4175            pCompiler->paWords[cWords].pchWord  = pchWord;
     4176            pCompiler->paWords[cWords].cchWord  = cchWord;
     4177            pCompiler->paWords[cWords].enmToken = enmToken;
     4178            cWords++;
     4179
     4180            /* Skip the work and any trailing blanks. */
     4181            cchWord += cchSkipAfter;
     4182            pchWord += cchWord;
     4183            cchLeft -= cchWord;
     4184            KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
     4185        } while (cchLeft > 0);
     4186    }
     4187    /*
     4188     * Have to deal with escaped EOLs.
     4189     */
     4190    else
     4191    {
     4192        const char *pszContent = pCompiler->pszContent;
     4193        do
     4194        {
     4195            size_t          cchSkipAfter = 0;
     4196            size_t          cchWord      = 1;
     4197            KMKCCEVALTOKEN  enmToken     = kKmkCcEvalToken_WordPlain;
     4198
     4199            /* Find the end of the current word. */
     4200            while (cchWord < cchLeft)
     4201            {
     4202                char ch = pchWord[cchWord];
     4203                if (!KMK_CC_EVAL_IS_SPACE_DOLLAR_OR_SLASH(ch))
     4204                { /* likely */ }
     4205                else if (ch == '$')
     4206                    enmToken = kKmkCcEvalToken_WordWithDollar;
     4207                else if (ch != '\\')
     4208                    break;
     4209                else if ((size_t)(&pchWord[cchWord] - pszContent) == pCompiler->paEscEols[iEscEol].offEsc)
     4210                {
     4211                    cchSkipAfter = pCompiler->paEscEols[iEscEol].offEol - pCompiler->paEscEols[iEscEol].offEsc
     4212                                 + pCompiler->cchEolSeq;
     4213                    iEscEol++;
     4214                    break;
     4215                }
     4216                cchWord++;
     4217            }
     4218
     4219            /* Add the word. */
     4220            KMK_CC_EVAL_ENSURE_WORDS(pCompiler, cWords + 1);
     4221            pCompiler->paWords[cWords].pchWord  = pchWord;
     4222            pCompiler->paWords[cWords].cchWord  = cchWord;
     4223            pCompiler->paWords[cWords].enmToken = enmToken;
     4224            cWords++;
     4225
     4226            /* Skip the work and any trailing blanks. */
     4227            cchWord += cchSkipAfter;
     4228            pchWord += cchWord;
     4229            cchLeft -= cchWord;
     4230            KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
     4231        } while (cchLeft > 0);
     4232    }
     4233    pCompiler->cWords = cWords;
     4234    return cWords;
     4235}
     4236
     4237
    38604238
    38614239
     
    41544532 * @param   cchLeft                 The number of chars left on the current line
    41554533 *                                  starting at @a pchWord.
    4156  * @param   fStripTrailingSpaces    Whether to strip trailing spaces.
    4157  */
    4158 static size_t kmk_cc_eval_prep_normal_line(PKMKCCEVALCOMPILER pCompiler, const char * const pchWord, size_t cchLeft,
    4159                                            int fStripTrailingSpaces)
     4534 */
     4535static size_t kmk_cc_eval_prep_normal_line(PKMKCCEVALCOMPILER pCompiler, const char * const pchWord, size_t cchLeft)
    41604536{
    41614537    size_t          cchRet;
     
    41744550    {
    41754551        cchRet = cchLeft;
    4176         if (fStripTrailingSpaces)
    4177             while (cchRet > 0 && KMK_CC_IS_SPACE_CH(pchWord[cchRet - 1]))
    4178                 cchRet--;
    41794552
    41804553        KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, 1);
     
    42034576        KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->cchContent);
    42044577        KMK_CC_ASSERT(offWord <  pCompiler->paEscEols[iEscEol].offEsc);
    4205         KMK_CC_ASSERT(offWord >= (iEscEol ? pCompiler->paEscEols[cEscEols - 1].offEol + pCompiler->cchEolSeq : pCompiler->offLine));
     4578        KMK_CC_ASSERT(offWord >= (iEscEol ? pCompiler->paEscEols[iEscEol - 1].offEol + pCompiler->cchEolSeq : pCompiler->offLine));
    42064579
    42074580        /* Make sure we've got more than enough segments to fill in. */
     
    42214594        pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = cchRet;
    42224595        pCompiler->paStrCopySegs[cSegs].pchSrc                = pchWord;
     4596        cSegs++;
    42234597
    42244598        offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq;
     
    42634637        if (offWord < offEsc)
    42644638        {
    4265             if (fStripTrailingSpaces)
    4266                 while (KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1]))
    4267                     offEsc--;
    42684639            cchSeg = offEsc - offWord;
    42694640            pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace ? -(ssize_t)cchSeg : (ssize_t)cchSeg;
     
    43314702    if (cchLeft)
    43324703    {
    4333         size_t           cchExpr = kmk_cc_eval_prep_normal_line(pCompiler, pchWord, cchLeft, 1 /*fStripTrailingSpaces*/);
    4334         PKMKCCEVALIFEXPR pInstr  = (PKMKCCEVALIFEXPR)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail,
    4335                                                                              KMKCCEVALIFEXPR_SIZE(cchExpr));
     4704        PKMKCCEVALIFEXPR pInstr;
     4705        size_t           cchExpr = kmk_cc_eval_prep_normal_line(pCompiler, pchWord, cchLeft);
     4706        kmk_cc_eval_strip_right_v(pCompiler->paStrCopySegs, &pCompiler->cStrCopySegs, &cchExpr);
     4707
     4708        pInstr = (PKMKCCEVALIFEXPR)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, KMKCCEVALIFEXPR_SIZE(cchExpr));
    43364709        kmk_cc_eval_strcpyv(pInstr->szExpr, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, cchExpr);
    43374710        pInstr->cchExpr = cchExpr;
    4338         pInstr->IfCore.Core.enmOpCode = kKmkCcEvalInstr_if;
     4711        pInstr->IfCore.Core.enmOpcode = kKmkCcEvalInstr_if;
    43394712        pInstr->IfCore.Core.iLine     = pCompiler->iLine;
    43404713        kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse);
     
    43694742        const char * const  pchVarNm     = pchWord;
    43704743        int                 fPlain;
     4744/** @todo this isn't quite right. It is a variable name, correct. However, it
     4745 *        doesn't need to subscribe entirely to the rules of a variable name.
     4746 *        Just find the end of the word, taking variable refs into account,
     4747 *        and consider it what we need. */
    43714748        pchWord = kmk_cc_eval_skip_var_name(pCompiler, pchWord, cchLeft, &cchLeft, &fPlain);
    43724749        KMK_CC_ASSERT(pCompiler->iEscEol == iSavedEscEol || !fPlain);
     
    43764753            PKMKCCEVALIFDEFPLAIN    pInstr;
    43774754            pInstr = (PKMKCCEVALIFDEFPLAIN)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
    4378             pInstr->IfCore.Core.enmOpCode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_plain : kKmkCcEvalInstr_ifndef_plain;
     4755            pInstr->IfCore.Core.enmOpcode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_plain : kKmkCcEvalInstr_ifndef_plain;
    43794756            pInstr->IfCore.Core.iLine     = pCompiler->iLine;
    43804757            pInstr->pszName = strcache2_add(&variable_strcache, pchVarNm, cchVarNm);
     
    43884765            char                   *pszCopy;
    43894766            pCompiler->iEscEol = iSavedEscEol;
    4390             cchCopy = kmk_cc_eval_prep_normal_line(pCompiler, pchVarNm, cchVarNm, 0 /*fStripTrailingSpaces*/);
     4767            cchCopy = kmk_cc_eval_prep_normal_line(pCompiler, pchVarNm, cchVarNm);
    43914768
    43924769            pInstr = (PKMKCCEVALIFDEFDYNAMIC)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
     
    43964773            kmk_cc_block_realign(pCompiler->ppBlockTail);
    43974774
    4398             pInstr->IfCore.Core.enmOpCode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_dynamic : kKmkCcEvalInstr_ifndef_dynamic;
     4775            pInstr->IfCore.Core.enmOpcode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_dynamic : kKmkCcEvalInstr_ifndef_dynamic;
    43994776            pInstr->IfCore.Core.iLine     = pCompiler->iLine;
    44004777            kmk_cc_eval_compile_string_exp_subprog(pCompiler, pszCopy, cchCopy, &pInstr->NameSubprog);
     
    45984975         * Initialize the instruction.
    45994976         */
    4600         pInstr->IfCore.Core.enmOpCode = fPositiveStmt ? kKmkCcEvalInstr_ifeq : kKmkCcEvalInstr_ifneq;
     4977        pInstr->IfCore.Core.enmOpcode = fPositiveStmt ? kKmkCcEvalInstr_ifeq : kKmkCcEvalInstr_ifneq;
    46014978        pInstr->IfCore.Core.iLine     = pCompiler->iLine;
    4602         kmk_cc_eval_do_subprogram_or_plain(pCompiler, &pInstr->Left, Left.pszCopy, Left.cchCopy, Left.fPlain);
    4603         kmk_cc_eval_do_subprogram_or_plain(pCompiler, &pInstr->Right, Right.pszCopy, Right.cchCopy, Right.fPlain);
     4979        kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Left, Left.pszCopy, Left.cchCopy, Left.fPlain);
     4980        kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Right, Right.pszCopy, Right.cchCopy, Right.fPlain);
    46044981        kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse);
    46054982
     
    47395116         * Initialize the instruction.
    47405117         */
    4741         pInstr->IfCore.Core.enmOpCode = fPositiveStmt ? kKmkCcEvalInstr_if1of : kKmkCcEvalInstr_ifn1of;
     5118        pInstr->IfCore.Core.enmOpcode = fPositiveStmt ? kKmkCcEvalInstr_if1of : kKmkCcEvalInstr_ifn1of;
    47425119        pInstr->IfCore.Core.iLine     = pCompiler->iLine;
    4743         kmk_cc_eval_do_subprogram_or_plain(pCompiler, &pInstr->Left, Left.pszCopy, Left.cchCopy, Left.fPlain);
    4744         kmk_cc_eval_do_subprogram_or_plain(pCompiler, &pInstr->Right, Right.pszCopy, Right.cchCopy, Right.fPlain);
     5120        kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Left, Left.pszCopy, Left.cchCopy, Left.fPlain);
     5121        kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Right, Right.pszCopy, Right.cchCopy, Right.fPlain);
    47455122        kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse);
    47465123
     
    47805157            /* Emit a jump instruction that will take us from the 'True' block to the 'endif'. */
    47815158            PKMKCCEVALJUMP  pInstr = (PKMKCCEVALJUMP)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
    4782             pInstr->Core.enmOpCode = kKmkCcEvalInstr_jump;
     5159            pInstr->Core.enmOpcode = kKmkCcEvalInstr_jump;
    47835160            pInstr->Core.iLine     = pCompiler->iLine;
    47845161            pInstr->pNext          = NULL;
     
    48965273
    48975274
    4898 static int kmk_cc_eval_do_include(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, KMKCCEVALINSTR enmInst)
    4899 {
     5275/**
     5276 * Parses a 'include file...', 'sinclude file...', '-include file...',
     5277 * 'includedep file...', 'includedep-queue file...' and
     5278 * 'includedep-flush file...'
     5279 *
     5280 * @returns 1 to indicate we've handled a keyword (see
     5281 *          kmk_cc_eval_try_handle_keyword).
     5282 * @param   pCompiler   The compiler state.
     5283 * @param   pchWord     First char after the include directive.
     5284 * @param   cchLeft     The number of chars left to parse on this line.
     5285 * @param   enmOpcode   The opcode for the include directive we're parsing.
     5286 */
     5287static int kmk_cc_eval_do_include(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, KMKCCEVALINSTR enmOpcode)
     5288{
     5289    KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
     5290    if (cchLeft)
     5291    {
     5292        /*
     5293         * Split what's left up into words.
     5294         */
     5295        unsigned cWords = kmk_cc_eval_parse_words(pCompiler, pchWord, cchLeft);
     5296        KMK_CC_EVAL_DPRINTF(("%s: cWords=%d\n", g_apszEvalInstrNms[enmOpcode], cWords));
     5297        if (cWords)
     5298        {
     5299            PKMKCCEVALINCLUDE pInstr = (PKMKCCEVALINCLUDE)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail,
     5300                                                                                  KMKCCEVALINCLUDE_SIZE(cWords));
     5301            pInstr->Core.enmOpcode = enmOpcode;
     5302            pInstr->Core.iLine     = 0;
     5303            pInstr->cFiles         = cWords;
     5304            kmk_cc_eval_init_spp_array_from_duplicated_words(pCompiler, cWords, pCompiler->paWords, pInstr->aFiles);
     5305            kmk_cc_block_realign(pCompiler->ppBlockTail);
     5306        }
     5307        else
     5308            KMK_CC_ASSERT(0);
     5309    }
     5310    else
     5311        KMK_CC_EVAL_DPRINTF(("%s: include without args\n", g_apszEvalInstrNms[enmOpcode]));
    49005312    return 1;
    49015313}
     
    49045316static int kmk_cc_eval_do_vpath(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
    49055317{
     5318    kmk_cc_eval_fatal(pCompiler, NULL, "vpath directive is not implemented\n");
    49065319    return 1;
    49075320}
     
    49105323static void kmk_cc_eval_handle_command(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
    49115324{
    4912 
     5325    kmk_cc_eval_fatal(pCompiler, pchWord, "command handling not implemented yet");
     5326}
     5327
     5328
     5329static int kmk_cc_eval_handle_recipe_cont_colon(PKMKCCEVALCOMPILER pCompiler, const char *pchWord0, size_t cchWord0,
     5330                                                const char *pchColon, size_t cchLeft, unsigned fQualifiers)
     5331{
     5332    kmk_cc_eval_fatal(pCompiler, pchWord0, "recipe handling not implemented yet");
     5333    return 1;
     5334}
     5335
     5336
     5337static int kmk_cc_eval_handle_recipe_cont_2nd_word(PKMKCCEVALCOMPILER pCompiler, const char *pchWord0, size_t cchWord0,
     5338                                                   const char *pchWord, size_t cchLeft, unsigned fQualifiers)
     5339{
     5340    kmk_cc_eval_fatal(pCompiler, pchWord, "recipe handling not implemented yet");
     5341    return 1;
    49135342}
    49145343
     
    49165345static void kmk_cc_eval_handle_recipe(PKMKCCEVALCOMPILER pCompiler, const char *pszEqual, const char *pchWord, size_t cchLeft)
    49175346{
    4918 
     5347    kmk_cc_eval_fatal(pCompiler, pchWord, "recipe handling not implemented yet");
     5348}
     5349
     5350static void kmk_cc_eval_end_of_recipe(PKMKCCEVALCOMPILER pCompiler)
     5351{
     5352    if (pCompiler->pRecipe)
     5353    {
     5354        /** @todo do stuff here. */
     5355    }
    49195356}
    49205357
     
    49335370 * @param   fQualifiers The qualifiers.
    49345371 */
    4935 static int kmk_cc_eval_do_var_undefine(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft,
    4936                                                 unsigned fQualifiers)
    4937 {
    4938 
     5372static int kmk_cc_eval_do_var_undefine(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers)
     5373{
     5374    kmk_cc_eval_fatal(pCompiler, pchWord, "undefine handling not implemented yet");
    49395375    return 1;
    49405376}
     
    49585394{
    49595395
     5396    KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
     5397    kmk_cc_eval_fatal(pCompiler, pchWord, "define handling not implemented yet");
    49605398    return 1;
    49615399}
    49625400
    49635401
    4964 static int kmk_cc_eval_try_handle_assignment(PKMKCCEVALCOMPILER pCompiler, const char *pchTmp,
    4965                                              const char *pchWord, size_t cchLeft, unsigned fQualifiers)
    4966 {
    4967     return 0;
     5402static int kmk_cc_eval_handle_assignment_or_recipe(PKMKCCEVALCOMPILER pCompiler, const char *pchTmp,
     5403                                                   const char *pchWord, size_t cchLeft, unsigned fQualifiers)
     5404{
     5405    /*
     5406     * We're currently at a word which may or may not be a variable name
     5407     * followed by an assignment operator, alternatively it must be a recipe.
     5408     * We need to figure this out and deal with it in the most efficient
     5409     * manner as this is a very common occurence.
     5410     */
     5411    unsigned const  iEscEolVarNm = pCompiler->iEscEol;
     5412    int             fPlainVarNm  = 1;
     5413    const char     *pchVarNm     = pchWord;
     5414    size_t          cchVarNm;
     5415    size_t          cch = 0;
     5416    char            ch;
     5417
     5418    /*
     5419     * The variable name.  Complicate by there being no requirement of a space
     5420     * preceeding the assignment operator, as well as that the variable name
     5421     * may include variable references with spaces (function++) in them.
     5422     */
     5423    for (;;)
     5424    {
     5425        if (cch < cchLeft)
     5426        { /*likely*/ }
     5427        else
     5428            kmk_cc_eval_fatal(pCompiler, &pchWord[cch], "Neither recipe nor variable assignment");
     5429
     5430        ch = pchWord[cch];
     5431        if (!KMK_CC_EVAL_IS_SPACE_DOLLAR_SLASH_OR_ASSIGN(ch))
     5432            cch++;
     5433        /* Space? */
     5434        else if (KMK_CC_EVAL_IS_SPACE(ch))
     5435        {
     5436            cchVarNm = cch;
     5437            pchWord += cch;
     5438            cchLeft -= cch;
     5439            KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
     5440            break;
     5441        }
     5442        /* Variable expansion may contain spaces, so handle specially. */
     5443        else if (ch == '$')
     5444        {
     5445            cch++;
     5446            if (cch < cchLeft)
     5447            {
     5448                char const chOpen = pchWord[cch];
     5449                if (chOpen == '(' || chOpen == '{')
     5450                {
     5451                    /*
     5452                     * Got a $(VAR) or ${VAR} to deal with here.  This may
     5453                     * include nested variable references and span multiple
     5454                     * lines (at least for function calls).
     5455                     *
     5456                     * We scan forward till we've found the corresponding
     5457                     * closing parenthesis, considering any open parentheses
     5458                     * of the same kind as worth counting, even if there are
     5459                     * no dollar preceeding them, just like GNU make does.
     5460                     */
     5461                    size_t const cchStart = cch - 1;
     5462                    char const   chClose  = chOpen == '(' ? ')' : '}';
     5463                    unsigned     cOpen    = 1;
     5464                    cch++;
     5465                    for (;;)
     5466                    {
     5467                        if (cch < cchLeft)
     5468                        {
     5469                            ch = pchWord[cch];
     5470                            if (!(KMK_CC_EVAL_IS_PAREN_OR_SLASH(ch)))
     5471                                cch++;
     5472                            else
     5473                            {
     5474                                cch++;
     5475                                if (ch == chClose)
     5476                                {
     5477                                    if (--cOpen == 0)
     5478                                        break;
     5479                                }
     5480                                else if (ch == chOpen)
     5481                                    cOpen++;
     5482                                else if (   ch == '\\'
     5483                                         && pCompiler->iEscEol < pCompiler->cEscEols
     5484                                         &&    (size_t)(&pchWord[cch] - pCompiler->pszContent)
     5485                                            == pCompiler->paEscEols[pCompiler->iEscEol].offEsc)
     5486                                {
     5487                                    cch += pCompiler->paEscEols[pCompiler->iEscEol].offEol
     5488                                         - pCompiler->paEscEols[pCompiler->iEscEol].offEsc
     5489                                         + pCompiler->cchEolSeq;
     5490                                    pCompiler->iEscEol++;
     5491                                }
     5492                            }
     5493                        }
     5494                        else if (cOpen == 1)
     5495                            kmk_cc_eval_fatal(pCompiler, &pchWord[cchStart], "Variable reference is missing '%c'", chClose);
     5496                        else
     5497                            kmk_cc_eval_fatal(pCompiler, &pchWord[cchStart],
     5498                                              "%u variable references are missing '%c'", cOpen, chClose);
     5499                    }
     5500                }
     5501                /* Single char variable name. */
     5502                else if (!KMK_CC_EVAL_IS_SPACE(chOpen))
     5503                {  /* likely */ }
     5504                else
     5505                    kmk_cc_eval_fatal(pCompiler, &pchWord[cch], "Expected variable name after '$', not end of line");
     5506            }
     5507            else
     5508                kmk_cc_eval_fatal(pCompiler, &pchWord[cch], "Neither recipe nor variable assignment");
     5509            fPlainVarNm = 0;
     5510        }
     5511        /* Check out potential recipe. */
     5512        else if (ch == ':')
     5513        {
     5514            if (   cch + 1 < cchLeft
     5515                && pchWord[cch + 1] != '=')
     5516            {
     5517                cchVarNm = cch;
     5518                pchWord += cch;
     5519                cchLeft -= cch;
     5520                break;
     5521            }
     5522#ifdef HAVE_DOS_PATHS
     5523            /* Don't confuse the first colon in:
     5524                    C:/Windows/System32/Kernel32.dll: C:/Windows/System32/NtDll.dll
     5525               for a recipe, it is only the second one which counts. */
     5526            else if (   cch == 1
     5527                     && isalpha((unsigned char)pchWord[0]))
     5528                cch++;
     5529#endif
     5530            else
     5531                return kmk_cc_eval_handle_recipe_cont_colon(pCompiler, pchWord, cch, pchWord + cch, cchLeft - cch, fQualifiers);
     5532        }
     5533        /* Check out assignment operator. */
     5534        else if (ch == '=')
     5535        {
     5536            if (cch)
     5537            {
     5538                char chPrev = pchWord[cch - 1];
     5539                if (chPrev == ':' || chPrev == '+' || chPrev == '?' || chPrev == '<')
     5540                    cch--;
     5541                cchVarNm = cch;
     5542                pchWord += cch;
     5543                cchLeft -= cch;
     5544                break;
     5545            }
     5546            else
     5547                kmk_cc_eval_fatal(pCompiler, pchWord, "Empty variable name.");
     5548        }
     5549        /* Check out potential escaped EOL sequence. */
     5550        else if (ch == '\\')
     5551        {
     5552            unsigned const iEscEol = pCompiler->iEscEol;
     5553            if (iEscEol >= pCompiler->cEscEols)
     5554                cch++;
     5555            else
     5556            {
     5557                size_t offCur = &pchWord[cch] - pCompiler->pszContent;
     5558                if (offCur < pCompiler->paEscEols[iEscEol].offEol)
     5559                    cch++;
     5560                else
     5561                {
     5562                    cchVarNm = cch;
     5563                    KMK_CC_ASSERT(offCur == pCompiler->paEscEols[iEscEol].offEol);
     5564                    cch = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq - offCur;
     5565                    pCompiler->iEscEol = iEscEol + 1;
     5566                    pchWord += cch;
     5567                    cchLeft -= cch;
     5568                    KMK_CC_EVAL_SKIP_SPACES(pCompiler, pchWord, cchLeft);
     5569                    break;
     5570                }
     5571            }
     5572        }
     5573        else
     5574            KMK_CC_ASSERT(0);
     5575    }
     5576
     5577    /*
     5578     * Check for assignment operator.
     5579     */
     5580    if (cchLeft)
     5581    {
     5582        size_t              cchValue;
     5583        PKMKCCEVALASSIGN    pInstr;
     5584        KMKCCEVALINSTR      enmOpCode;
     5585        int                 fPlainValue;
     5586        char               *pszValue;
     5587
     5588        ch = *pchWord;
     5589        if (ch == '=')
     5590        {
     5591            enmOpCode = kKmkCcEvalInstr_assign_recursive;
     5592            pchWord++;
     5593            cchLeft--;
     5594        }
     5595        else if (cchLeft >= 2 && pchWord[1] == '=')
     5596        {
     5597            if (ch == ':')
     5598                enmOpCode = kKmkCcEvalInstr_assign_simple;
     5599            else if (ch == '+')
     5600                enmOpCode = kKmkCcEvalInstr_assign_append;
     5601            else if (ch == '<')
     5602                enmOpCode = kKmkCcEvalInstr_assign_prepend;
     5603            else if (ch == '?')
     5604                enmOpCode = kKmkCcEvalInstr_assign_if_new;
     5605            else
     5606                return kmk_cc_eval_handle_recipe_cont_2nd_word(pCompiler, pchVarNm, cchVarNm, pchWord, cchLeft, fQualifiers);
     5607            pchWord += 2;
     5608            cchLeft -= 2;
     5609        }
     5610        else
     5611            return kmk_cc_eval_handle_recipe_cont_2nd_word(pCompiler, pchVarNm, cchVarNm, pchWord, cchLeft, fQualifiers);
     5612
     5613        /*
     5614         * Skip leading spaces, if any and prep the value for copying.
     5615         */
     5616        KMK_CC_EVAL_SKIP_SPACES(pCompiler, pchWord, cchLeft);
     5617        cchValue    = kmk_cc_eval_prep_normal_line(pCompiler, pchWord, cchLeft);
     5618        fPlainValue = memchr(pchWord, '$', cchLeft) == NULL;
     5619
     5620        /*
     5621         * Emit the instruction.
     5622         */
     5623        kmk_cc_eval_end_of_recipe(pCompiler);
     5624
     5625        pInstr = (PKMKCCEVALASSIGN)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
     5626        pInstr->Core.enmOpcode = enmOpCode;
     5627        pInstr->Core.iLine     = pCompiler->iLine;
     5628        pInstr->fExport        = (fQualifiers & KMK_CC_EVAL_QUALIFIER_EXPORT)   != 0;
     5629        pInstr->fOverride      = (fQualifiers & KMK_CC_EVAL_QUALIFIER_OVERRIDE) != 0;
     5630        pInstr->fPrivate       = (fQualifiers & KMK_CC_EVAL_QUALIFIER_PRIVATE)  != 0;
     5631        pInstr->fLocal         = (fQualifiers & KMK_CC_EVAL_QUALIFIER_LOCAL)    != 0;
     5632
     5633        /* We copy the value before messing around with the variable name since
     5634           we have to do more iEolEsc saves & restores the other way around. */
     5635        pszValue = kmk_cc_eval_strdup_prepped(pCompiler, cchValue);
     5636        if (fPlainVarNm)
     5637            pchVarNm = strcache2_add(&variable_strcache, pchVarNm, cchVarNm);
     5638        else
     5639        {
     5640            pCompiler->iEscEol = iEscEolVarNm;
     5641            cchVarNm = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchVarNm, cchVarNm);
     5642            pchVarNm = kmk_cc_eval_strdup_prepped(pCompiler, cchVarNm);
     5643        }
     5644        kmk_cc_block_realign(pCompiler->ppBlockTail);
     5645        KMK_CC_EVAL_DPRINTF(("%s: '%s' '%s'\n", g_apszEvalInstrNms[enmOpCode], pchVarNm, pszValue));
     5646
     5647        kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Variable, pchVarNm, cchVarNm, fPlainVarNm);
     5648        kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Value, pszValue, cchValue, fPlainValue);
     5649
     5650        pInstr->pNext = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail);
     5651    }
     5652    else
     5653        kmk_cc_eval_fatal(pCompiler, pchWord, "Neither recipe nor variable assignment");
     5654    return 1;
    49685655}
    49695656
     
    49745661 * The 'local' directive must be first and it does not permit any qualifiers at
    49755662 * the moment.  Should any be added later, they will have to come after 'local'.
     5663 *
     5664 * @returns 1 to indicate we've handled a keyword (see
     5665 *          kmk_cc_eval_try_handle_keyword).
     5666 * @param   pCompiler   The compiler state.
     5667 * @param   pchWord     First char after 'local'.
     5668 * @param   cchLeft     The number of chars left to parse on this line.
     5669 * @param   fQualifiers The qualifiers.
     5670 */
     5671static int kmk_cc_eval_do_var_local(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
     5672{
     5673    KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
     5674    if (cchLeft)
     5675    {
     5676        /*
     5677         * Find the end of the variable name.
     5678         */
     5679
     5680    }
     5681    else
     5682        kmk_cc_eval_fatal(pCompiler, pchWord, "Expected variable name, assignment operator and value after 'local'");
     5683    return 1;
     5684}
     5685
     5686
     5687/**
     5688 * Parses 'export [variable]' and 'export [qualifiers] variable = value'
     5689 * expressions.
     5690 *
     5691 * When we find the 'export' directive at the start of a line, we need to
     5692 * continue parsing with till we can tell the difference between the two forms.
    49765693 *
    49775694 * @returns 1 to indicate we've handled a keyword (see
     
    49825699 * @param   fQualifiers The qualifiers.
    49835700 */
    4984 static int kmk_cc_eval_do_var_local(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
    4985 {
    4986 
    4987     return 1;
    4988 }
    4989 
    4990 
    4991 /**
    4992  * Parses 'export [variable]' and 'export [qualifiers] variable = value'
    4993  * expressions.
    4994  *
    4995  * When we find the 'export' directive at the start of a line, we need to
    4996  * continue parsing with till we can tell the difference between the two forms.
    4997  *
    4998  * @returns 1 to indicate we've handled a keyword (see
    4999  *          kmk_cc_eval_try_handle_keyword).
    5000  * @param   pCompiler   The compiler state.
    5001  * @param   pchWord     First char after 'define'.
    5002  * @param   cchLeft     The number of chars left to parse on this line.
    5003  * @param   fQualifiers The qualifiers.
    5004  */
    50055701static int kmk_cc_eval_handle_var_export(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers)
    50065702{
    5007 
     5703    kmk_cc_eval_fatal(pCompiler, pchWord, "export not implemented yet");
    50085704    return 1;
    50095705}
     
    50345730                    return kmk_cc_eval_do_var_define(pCompiler, pchWord + 6, cchLeft - 6, fQualifiers);
    50355731
    5036                 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6))   /* special */
    5037                     return kmk_cc_eval_handle_var_export(pCompiler, pchWord + 6, cchLeft - 6, fQualifiers);
    5038 
    50395732                if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8)) /* final */
    50405733                    return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 6, cchLeft - 6, fQualifiers);
    50415734
     5735                if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6))
     5736                {
     5737                    if (!(fQualifiers & KMK_CC_EVAL_QUALIFIER_EXPORT))
     5738                        fQualifiers |= KMK_CC_EVAL_QUALIFIER_EXPORT;
     5739                    else
     5740                        kmk_cc_eval_warn(pCompiler, pchWord, "'export' qualifier repeated");
     5741                    pchWord += 6;
     5742                    cchLeft -= 6;
     5743                    continue;
     5744                }
     5745
    50425746                if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8))
    50435747                {
    5044                     /** @todo warn if repeated. */
    5045                     fQualifiers |= KMK_CC_EVAL_QUALIFIER_OVERRIDE;
     5748                    if (!(fQualifiers & KMK_CC_EVAL_QUALIFIER_OVERRIDE))
     5749                        fQualifiers |= KMK_CC_EVAL_QUALIFIER_OVERRIDE;
     5750                    else
     5751                        kmk_cc_eval_warn(pCompiler, pchWord, "'override' qualifier repeated");
    50465752                    pchWord += 8;
    50475753                    cchLeft -= 8;
     
    50515757                if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7))
    50525758                {
    5053                     /** @todo warn if repeated. */
    5054                     fQualifiers |= KMK_CC_EVAL_QUALIFIER_PRIVATE;
     5759                    if (!(fQualifiers & KMK_CC_EVAL_QUALIFIER_PRIVATE))
     5760                        fQualifiers |= KMK_CC_EVAL_QUALIFIER_PRIVATE;
     5761                    else
     5762                        kmk_cc_eval_warn(pCompiler, pchWord, "'private' qualifier repeated");
    50555763                    pchWord += 7;
    50565764                    cchLeft -= 7;
     
    50675775                const char *pchEqual = (const char *)memchr(pchWord, '=', cchLeft);
    50685776                if (pchEqual)
    5069                     return kmk_cc_eval_try_handle_assignment(pCompiler, pchEqual, pchWord, cchLeft, fQualifiers);
     5777                    return kmk_cc_eval_handle_assignment_or_recipe(pCompiler, pchEqual, pchWord, cchLeft, fQualifiers);
    50705778            }
    50715779            return 0;
     
    54406148                    {
    54416149                        pchTmp = (const char *)memchr(pchWord, '=', cchLeft);
    5442                         if (   !pchTmp
    5443                             || !kmk_cc_eval_try_handle_assignment(&Compiler, pchTmp, pchWord, cchLeft, 0) )
     6150                        if (pchTmp)
     6151                            kmk_cc_eval_handle_assignment_or_recipe(&Compiler, pchTmp, pchWord, cchLeft, 0);
     6152                        else
    54446153                            kmk_cc_eval_handle_recipe(&Compiler, pchTmp, pchWord, cchLeft);
    54456154                    }
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette