VirtualBox

source: kBuild/trunk/src/kmk/kmk_cc_exec.c@ 3219

Last change on this file since 3219 was 3154, checked in by bird, 6 years ago

kmk_cc_exec: Some more work.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 269.3 KB
Line 
1#ifdef CONFIG_WITH_COMPILER
2/* $Id: kmk_cc_exec.c 3154 2018-03-15 23:35:33Z bird $ */
3/** @file
4 * kmk_cc - Make "Compiler".
5 */
6
7/*
8 * Copyright (c) 2015-2017 knut st. osmundsen <bird-kBuild-spam-xiiv@anduin.net>
9 *
10 * This file is part of kBuild.
11 *
12 * kBuild is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * kBuild is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
24 *
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "makeint.h"
32
33#include "dep.h"
34#include "variable.h"
35#include "rule.h"
36#include "debug.h"
37#include "hash.h"
38#include <ctype.h>
39#ifdef HAVE_STDINT_H
40# include <stdint.h>
41#endif
42#include <stdarg.h>
43#include <assert.h>
44#include "k/kDefs.h"
45#include "k/kTypes.h"
46
47
48/*********************************************************************************************************************************
49* Defined Constants And Macros *
50*********************************************************************************************************************************/
51/** @def KMK_CC_WITH_STATS
52 * Enables the collection of extra statistics. */
53#ifndef KMK_CC_WITH_STATS
54# ifdef CONFIG_WITH_MAKE_STATS
55# define KMK_CC_WITH_STATS
56# endif
57#endif
58
59/** @def KMK_CC_STRICT
60 * Indicates whether assertions and other checks are enabled. */
61#ifndef KMK_CC_STRICT
62# ifndef NDEBUG
63# define KMK_CC_STRICT
64# endif
65#endif
66
67#ifdef KMK_CC_STRICT
68# ifdef _MSC_VER
69# define KMK_CC_ASSERT(a_TrueExpr) do { if (!(a_TrueExpr)) __debugbreak(); } while (0)
70# elif defined(__GNUC__) && (defined(KBUILD_ARCH_X86) || defined(KBUILD_ARCH_AMD64))
71# define KMK_CC_ASSERT(a_TrueExpr) do { if (!(a_TrueExpr)) __asm__ __volatile__("int3;nop"); } while (0)
72# else
73# define KMK_CC_ASSERT(a_TrueExpr) assert(a_TrueExpr)
74# endif
75#else
76# define KMK_CC_ASSERT(a_TrueExpr) do {} while (0)
77#endif
78#define KMK_CC_ASSERT_ALIGNED(a_uValue, a_uAlignment) \
79 KMK_CC_ASSERT( ((a_uValue) & ((a_uAlignment) - 1)) == 0 )
80
81
82/** @def KMK_CC_OFFSETOF
83 * Offsetof for simple stuff. */
84#if defined(__GNUC__)
85# define KMK_CC_OFFSETOF(a_Struct, a_Member) __builtin_offsetof(a_Struct, a_Member)
86#else
87# define KMK_CC_OFFSETOF(a_Struct, a_Member) ( (uintptr_t)&( ((a_Struct *)(void *)0)->a_Member) )
88#endif
89
90/** def KMK_CC_SIZEOF_MEMBER */
91#define KMK_CC_SIZEOF_MEMBER(a_Struct, a_Member) ( sizeof( ((a_Struct *)(void *)0x1000)->a_Member) )
92
93/** @def KMK_CC_SIZEOF_VAR_STRUCT
94 * Size of a struct with a variable sized array as the final member. */
95#define KMK_CC_SIZEOF_VAR_STRUCT(a_Struct, a_FinalArrayMember, a_cArray) \
96 ( KMK_CC_OFFSETOF(a_Struct, a_FinalArrayMember) + KMK_CC_SIZEOF_MEMBER(a_Struct, a_FinalArrayMember) * (a_cArray) )
97
98
99
100/** @def KMK_CC_STATIC_ASSERT_EX
101 * Compile time assertion with text.
102 */
103#ifdef _MSC_VER_
104# if _MSC_VER >= 1600
105# define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) static_assert(a_Expr, a_szExpl)
106# else
107# define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) typedef int RTASSERTVAR[(a_Expr) ? 1 : 0]
108# endif
109#elif defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__)
110# define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) static_assert(a_Expr, a_szExpl)
111#elif !defined(__GNUC__) && !defined(__IBMC__) && !defined(__IBMCPP__)
112# define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) typedef int KMK_CC_STATIC_ASSERT_EX_TYPE[(a_Expr) ? 1 : 0]
113#else
114# define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) extern int KMK_CC_STATIC_ASSERT_EX_VAR[(a_Expr) ? 1 : 0]
115extern int KMK_CC_STATIC_ASSERT_EX_VAR[1];
116#endif
117/** @def KMK_CC_STATIC_ASSERT
118 * Compile time assertion, simple variant.
119 */
120#define KMK_CC_STATIC_ASSERT(a_Expr) KMK_CC_STATIC_ASSERT_EX(a_Expr, #a_Expr)
121
122
123/** Aligns a size for the block allocator. */
124#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
133
134/** Block allocator logging. */
135//#define KMK_CC_BLOCK_LOGGING_ENABLED
136#ifdef KMK_CC_BLOCK_LOGGING_ENABLED
137# define KMK_CC_BLOCK_DPRINTF_UNPACK(...) __VA_ARGS__
138# define KMK_CC_BLOCK_DPRINTF(a) fprintf(stderr, KMK_CC_BLOCK_DPRINTF_UNPACK a)
139#else
140# define KMK_CC_BLOCK_DPRINTF(a) do { } while (0)
141#endif
142
143
144/** @defgroup grp_kmk_cc_evalprog Makefile Evaluation
145 * @{
146 */
147#define KMK_CC_EVAL_LOGGING_ENABLED
148#ifdef KMK_CC_EVAL_LOGGING_ENABLED
149# define KMK_CC_EVAL_DPRINTF_UNPACK(...) __VA_ARGS__
150# define KMK_CC_EVAL_DPRINTF(a) fprintf(stderr, KMK_CC_EVAL_DPRINTF_UNPACK a)
151#else
152# define KMK_CC_EVAL_DPRINTF(a) do { } while (0)
153#endif
154
155/** @name KMK_CC_EVAL_QUALIFIER_XXX - Variable qualifiers.
156 * @{ */
157#define KMK_CC_EVAL_QUALIFIER_LOCAL 1
158#define KMK_CC_EVAL_QUALIFIER_EXPORT 2
159#define KMK_CC_EVAL_QUALIFIER_OVERRIDE 4
160#define KMK_CC_EVAL_QUALIFIER_PRIVATE 8
161/** @} */
162
163/** Eval: Max makefile size we accept as input (in bytes). */
164#define KMK_CC_EVAL_MAX_COMPILE_SIZE (16*1024*1024)
165
166/** Eval: Max nesting depth of makefile conditionals.
167 * Affects stack usage in kmk_cc_eval_compile_worker. */
168#define KMK_CC_EVAL_MAX_IF_DEPTH 32
169/** Eval: Maximum number of escaped end of line sequences to track.
170 * Affects stack usage in kmk_cc_eval_compile_worker, but not the actual
171 * number of consequtive escaped newlines in the input file/variable. */
172#define KMK_CC_EVAL_MAX_ESC_EOLS 2
173
174/** Minimum keyword length. */
175#define KMK_CC_EVAL_KEYWORD_MIN 2
176/** Maximum keyword length. */
177#define KMK_CC_EVAL_KEYWORD_MAX 16
178
179/** @name KMK_CC_EVAL_CH_XXX - flags found in g_abEvalCcChars.
180 * @{ */
181/** Normal character, nothing special. */
182#define KMK_CC_EVAL_CH_NORMAL UINT16_C(0)
183/** Blank character. */
184#define KMK_CC_EVAL_CH_BLANK UINT16_C(1)
185#define KMK_CC_EVAL_IS_BLANK(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_BLANK)
186/** Space character. */
187#define KMK_CC_EVAL_CH_SPACE UINT16_C(2)
188#define KMK_CC_EVAL_IS_SPACE(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_SPACE)
189/** Space character or potential EOL escape backslash. */
190#define KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH UINT16_C(4)
191#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)
192/** Anything we need to take notice of when parsing something could be a
193 * variable name or a recipe.
194 * All space characters, backslash (EOL escape), variable expansion dollar,
195 * variable assignment operator chars, recipe colon and recipe percent. */
196#define KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE UINT16_C(8)
197#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)
198/** Dollar character (possible variable expansion). */
199#define KMK_CC_EVAL_CH_DOLLAR UINT16_C(16)
200#define KMK_CC_EVAL_IS_DOLLAR(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_DOLLAR)
201/** Dollar character (possible variable expansion). */
202#define KMK_CC_EVAL_CH_BACKSLASH UINT16_C(32)
203#define KMK_CC_EVAL_IS_BACKSLASH(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_BACKSLASH)
204/** Possible EOL character. */
205#define KMK_CC_EVAL_CH_EOL_CANDIDATE UINT16_C(64)
206#define KMK_CC_EVAL_IS_EOL_CANDIDATE(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_EOL_CANDIDATE)
207/** First character in a keyword. */
208#define KMK_CC_EVAL_CH_1ST_IN_KEYWORD UINT16_C(128)
209#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)
210/** Second character in a keyword. */
211#define KMK_CC_EVAL_CH_2ND_IN_KEYWORD UINT16_C(256)
212#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)
213/** First character in a variable qualifier keyword or 'define'. */
214#define KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD UINT16_C(512)
215#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)
216/** Used when parsing variable names, looking for the end of a nested
217 * variable reference. Matches parentheses and backslash (escaped eol). */
218#define KMK_CC_EVAL_CH_PAREN_OR_SLASH UINT16_C(1024)
219#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)
220/** Used when parsing ifeq/ifneq (,) sequences.
221 * Matches parentheses, comma and dollar (for non-plain string detection). */
222#define KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR UINT16_C(2048)
223#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)
224
225/** Test of space or dollar characters. */
226#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))
227/** Test of space, dollar or backslash (possible EOL escape) characters. */
228#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))
229/** Test of space, dollar, backslash (possible EOL escape) or variable
230 * assingment characters. */
231#define KMK_CC_EVAL_IS_SPACE_DOLLAR_SLASH_OR_ASSIGN(a_ch) \
232 (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))
233/** @} */
234
235/** Sets a bitmap entry.
236 * @param a_abBitmap Typically g_abEvalCcChars.
237 * @param a_ch The character to set.
238 * @param a_uVal The value to OR in. */
239#define KMK_CC_EVAL_BM_OR(g_abBitmap, a_ch, a_uVal) do { (g_abBitmap)[(unsigned char)(a_ch)] |= (a_uVal); } while (0)
240
241/** Gets a bitmap entry.
242 * @returns The value corresponding to @a a_ch.
243 * @param a_abBitmap Typically g_abEvalCcChars.
244 * @param a_ch The character to set. */
245#define KMK_CC_EVAL_BM_GET(g_abBitmap, a_ch) ( (g_abBitmap)[(unsigned char)(a_ch)] )
246
247/** @} */
248
249
250/*********************************************************************************************************************************
251* Structures and Typedefs *
252*********************************************************************************************************************************/
253/**
254 * Block of instructions.
255 *
256 * To avoid wasting space on "next" pointers, as well as a lot of time walking
257 * these chains when destroying programs, we work with blocks of instructions.
258 */
259typedef struct kmk_cc_block
260{
261 /** The pointer to the next block (LIFO). */
262 struct kmk_cc_block *pNext;
263 /** The size of this block. */
264 uint32_t cbBlock;
265 /** The offset of the next free byte in the block. When set to cbBlock the
266 * block is 100% full. */
267 uint32_t offNext;
268} KMKCCBLOCK;
269typedef KMKCCBLOCK *PKMKCCBLOCK;
270
271
272/** @defgroup grp_kmk_cc_exp String Expansion
273 * @{*/
274
275/**
276 * String expansion statistics.
277 */
278typedef struct KMKCCEXPSTATS
279{
280 /** Recent average size. */
281 uint32_t cchAvg;
282} KMKCCEXPSTATS;
283typedef KMKCCEXPSTATS *PKMKCCEXPSTATS;
284
285/**
286 * Expansion instructions.
287 */
288typedef enum KMKCCEXPINSTR
289{
290 /** Copy a plain string. */
291 kKmkCcExpInstr_CopyString = 0,
292 /** Insert an expanded variable value, which name we already know. */
293 kKmkCcExpInstr_PlainVariable,
294 /** Insert an expanded variable value, the name is dynamic (sub prog). */
295 kKmkCcExpInstr_DynamicVariable,
296 /** Insert an expanded variable value, which name we already know, doing
297 * search an replace on a string. */
298 kKmkCcExpInstr_SearchAndReplacePlainVariable,
299 /** Insert the output of function that requires no argument expansion. */
300 kKmkCcExpInstr_PlainFunction,
301 /** Insert the output of function that requires dynamic expansion of one ore
302 * more arguments. (Dynamic is perhaps not such a great name, but whatever.) */
303 kKmkCcExpInstr_DynamicFunction,
304 /** Jump to a new instruction block. */
305 kKmkCcExpInstr_Jump,
306 /** We're done, return. Has no specific structure. */
307 kKmkCcExpInstr_Return,
308 /** The end of valid instructions (exclusive). */
309 kKmkCcExpInstr_End
310} KMKCCEXPINSTR;
311
312/** Instruction core. */
313typedef struct kmk_cc_exp_core
314{
315 /** The instruction opcode number (KMKCCEXPINSTR). */
316 KMKCCEXPINSTR enmOpcode;
317} KMKCCEXPCORE;
318typedef KMKCCEXPCORE *PKMKCCEXPCORE;
319
320/**
321 * String expansion subprogram.
322 */
323#pragma pack(1) /* save some precious bytes */
324typedef struct kmk_cc_exp_subprog
325{
326 /** Pointer to the first instruction. */
327 PKMKCCEXPCORE pFirstInstr;
328 /** Statistics. */
329 KMKCCEXPSTATS Stats;
330} KMKCCEXPSUBPROG;
331#pragma pack()
332typedef KMKCCEXPSUBPROG *PKMKCCEXPSUBPROG;
333KMK_CC_STATIC_ASSERT(sizeof(KMKCCEXPSUBPROG) == 12 || sizeof(void *) != 8);
334
335
336/**
337 * String expansion subprogram or plain string.
338 */
339#pragma pack(1) /* save some precious bytes */
340typedef struct kmk_cc_exp_subprog_or_string
341{
342 /** Either a plain string pointer or a subprogram. */
343 union
344 {
345 /** Subprogram for expanding this argument. */
346 KMKCCEXPSUBPROG Subprog;
347 /** Pointer to the plain string. */
348 struct
349 {
350 /** Pointer to the string. */
351 const char *psz;
352 /** String length. */
353 uint32_t cch;
354 } Plain;
355 } u;
356 /** Set if subprogram (u.Subprog), clear if plain string (u.Plain). */
357 uint8_t fSubprog;
358 /** Set if the plain string is kept in the variable_strcache.
359 * @remarks Here rather than in u.Plain to make use of alignment padding. */
360 uint8_t fPlainIsInVarStrCache;
361 /** Context/user specific. */
362 uint8_t bUser;
363 /** Context/user specific #2. */
364 uint8_t bUser2;
365} KMKCCEXPSUBPROGORPLAIN;
366#pragma pack()
367typedef KMKCCEXPSUBPROGORPLAIN *PKMKCCEXPSUBPROGORPLAIN;
368KMK_CC_STATIC_ASSERT( sizeof(void *) == 8
369 ? sizeof(KMKCCEXPSUBPROGORPLAIN) == 16
370 : sizeof(void *) == 4
371 ? sizeof(KMKCCEXPSUBPROGORPLAIN) == 12
372 : 1);
373
374/**
375 * kKmkCcExpInstr_CopyString instruction format.
376 */
377typedef struct kmk_cc_exp_copy_string
378{
379 /** The core instruction. */
380 KMKCCEXPCORE Core;
381 /** The number of bytes to copy. */
382 uint32_t cchCopy;
383 /** Pointer to the source string (not terminated at cchCopy). */
384 const char *pachSrc;
385} KMKCCEXPCOPYSTRING;
386typedef KMKCCEXPCOPYSTRING *PKMKCCEXPCOPYSTRING;
387
388/**
389 * kKmkCcExpInstr_PlainVariable instruction format.
390 */
391typedef struct kmk_cc_exp_plain_variable
392{
393 /** The core instruction. */
394 KMKCCEXPCORE Core;
395 /** The name of the variable (points into variable_strcache). */
396 const char *pszName;
397} KMKCCEXPPLAINVAR;
398typedef KMKCCEXPPLAINVAR *PKMKCCEXPPLAINVAR;
399
400/**
401 * kKmkCcExpInstr_DynamicVariable instruction format.
402 */
403typedef struct kmk_cc_exp_dynamic_variable
404{
405 /** The core instruction. */
406 KMKCCEXPCORE Core;
407 /** The subprogram that will give us the variable name. */
408 KMKCCEXPSUBPROG Subprog;
409 /** Where to continue after this instruction. (This is necessary since the
410 * instructions of the subprogram are emitted after this instruction.) */
411 PKMKCCEXPCORE pNext;
412} KMKCCEXPDYNVAR;
413typedef KMKCCEXPDYNVAR *PKMKCCEXPDYNVAR;
414
415/**
416 * kKmkCcExpInstr_SearchAndReplacePlainVariable instruction format.
417 */
418typedef struct kmk_cc_exp_sr_plain_variable
419{
420 /** The core instruction. */
421 KMKCCEXPCORE Core;
422 /** Where to continue after this instruction. (This is necessary since the
423 * instruction contains string data of variable size.) */
424 PKMKCCEXPCORE pNext;
425 /** The name of the variable (points into variable_strcache). */
426 const char *pszName;
427 /** Search pattern. */
428 const char *pszSearchPattern;
429 /** Replacement pattern. */
430 const char *pszReplacePattern;
431 /** Offset into pszSearchPattern of the significant '%' char. */
432 uint32_t offPctSearchPattern;
433 /** Offset into pszReplacePattern of the significant '%' char. */
434 uint32_t offPctReplacePattern;
435} KMKCCEXPSRPLAINVAR;
436typedef KMKCCEXPSRPLAINVAR *PKMKCCEXPSRPLAINVAR;
437
438/**
439 * Instruction format parts common to both kKmkCcExpInstr_PlainFunction and
440 * kKmkCcExpInstr_DynamicFunction.
441 */
442typedef struct kmk_cc_exp_function_core
443{
444 /** The core instruction. */
445 KMKCCEXPCORE Core;
446 /** Number of arguments. */
447 uint32_t cArgs; /**< @todo uint16_t to save 7 bytes of unecessary alignment padding on 64-bit systems, or merge fDirty into this member. */
448 /** Set if the function could be modifying the input arguments. */
449 uint8_t fDirty;
450 /** Where to continue after this instruction. (This is necessary since the
451 * instructions are of variable size and may be followed by string data.) */
452 PKMKCCEXPCORE pNext;
453 /**
454 * Pointer to the function table entry.
455 *
456 * @returns New variable buffer position.
457 * @param pchDst Current variable buffer position.
458 * @param papszArgs Pointer to a NULL terminated array of argument strings.
459 * @param pszFuncName The name of the function being called.
460 */
461 char * (*pfnFunction)(char *pchDst, char **papszArgs, const char *pszFuncName);
462 /** Pointer to the function name in the variable string cache. */
463 const char *pszFuncName;
464} KMKCCEXPFUNCCORE;
465typedef KMKCCEXPFUNCCORE *PKMKCCEXPFUNCCORE;
466
467/**
468 * Instruction format for kKmkCcExpInstr_PlainFunction.
469 */
470typedef struct kmk_cc_exp_plain_function
471{
472 /** The bits comment to both plain and dynamic functions. */
473 KMKCCEXPFUNCCORE FnCore;
474 /** Variable sized argument list (cArgs + 1 in length, last entry is NULL).
475 * The string pointers are to memory following this instruction, to memory in
476 * the next block or to memory in the variable / makefile we're working on
477 * (if zero terminated appropriately). */
478 const char *apszArgs[1];
479} KMKCCEXPPLAINFUNC;
480typedef KMKCCEXPPLAINFUNC *PKMKCCEXPPLAINFUNC;
481/** Calculates the size of an KMKCCEXPPLAINFUNC structure with the apszArgs
482 * member holding a_cArgs entries plus a NULL terminator. */
483#define KMKCCEXPPLAINFUNC_SIZE(a_cArgs) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEXPDYNFUNC, aArgs, (a_cArgs) + 1)
484
485/**
486 * Instruction format for kKmkCcExpInstr_DynamicFunction.
487 */
488typedef struct kmk_cc_exp_dyn_function
489{
490 /** The bits comment to both plain and dynamic functions. */
491 KMKCCEXPFUNCCORE FnCore;
492 /** Variable sized argument list (FnCore.cArgs in length).
493 * The subprograms / strings are allocated after this array (or in the next
494 * block). */
495 KMKCCEXPSUBPROGORPLAIN aArgs[1];
496} KMKCCEXPDYNFUNC;
497typedef KMKCCEXPDYNFUNC *PKMKCCEXPDYNFUNC;
498/** Calculates the size of an KMKCCEXPDYNFUNC structure with the apszArgs
499 * member holding a_cArgs entries (no zero terminator). */
500#define KMKCCEXPDYNFUNC_SIZE(a_cArgs) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEXPDYNFUNC, aArgs, a_cArgs)
501
502/**
503 * Instruction format for kKmkCcExpInstr_Jump.
504 */
505typedef struct kmk_cc_exp_jump
506{
507 /** The core instruction. */
508 KMKCCEXPCORE Core;
509 /** Where to jump to (new instruction block, typically). */
510 PKMKCCEXPCORE pNext;
511} KMKCCEXPJUMP;
512typedef KMKCCEXPJUMP *PKMKCCEXPJUMP;
513
514/**
515 * String expansion program.
516 */
517typedef struct kmk_cc_expandprog
518{
519 /** Pointer to the first instruction for this program. */
520 PKMKCCEXPCORE pFirstInstr;
521 /** List of blocks for this program (LIFO). */
522 PKMKCCBLOCK pBlockTail;
523 /** Statistics. */
524 KMKCCEXPSTATS Stats;
525#ifdef KMK_CC_STRICT
526 /** The hash of the input string. Used to check that we get all the change
527 * notifications we require. */
528 uint32_t uInputHash;
529#endif
530 /** Reference count. */
531 uint32_t volatile cRefs;
532} KMKCCEXPPROG;
533/** Pointer to a string expansion program. */
534typedef KMKCCEXPPROG *PKMKCCEXPPROG;
535
536/** @} */
537
538
539/** @addtogroup grp_kmk_cc_evalprog
540 * @{ */
541
542/** Pointer to a makefile evaluation program. */
543typedef struct kmk_cc_evalprog *PKMKCCEVALPROG;
544
545/**
546 * Makefile evaluation instructions.
547 */
548typedef enum KMKCCEVALINSTR
549{
550 /** Jump instruction - KMKCCEVALJUMP. */
551 kKmkCcEvalInstr_jump = 0,
552
553 /** [local|override|export] variable = value - KMKCCEVALASSIGN.
554 * @note Can be used for target-specific variables. */
555 kKmkCcEvalInstr_assign_recursive,
556 /** [local|override|export] variable := value - KMKCCEVALASSIGN.
557 * @note Can be used for target-specific variables. */
558 kKmkCcEvalInstr_assign_simple,
559 /** [local|override|export] variable += value - KMKCCEVALASSIGN.
560 * @note Can be used for target-specific variables. */
561 kKmkCcEvalInstr_assign_append,
562 /** [local|override|export] variable -= value - KMKCCEVALASSIGN.
563 * @note Can be used for target-specific variables. */
564 kKmkCcEvalInstr_assign_prepend,
565 /** [local|override|export] variable ?= value - KMKCCEVALASSIGN.
566 * @note Can be used for target-specific variables. */
567 kKmkCcEvalInstr_assign_if_new,
568 /** [local|override|export] define variable ... endef - KMKCCEVALASSIGNDEF. */
569 kKmkCcEvalInstr_assign_define,
570
571 /** export variable1 [variable2...] - KMKCCEVALVARIABLES. */
572 kKmkCcEvalInstr_export,
573 /** unexport variable1 [variable2...] - KMKCCEVALVARIABLES. */
574 kKmkCcEvalInstr_unexport,
575 /** export - KMKCCEVALCORE. */
576 kKmkCcEvalInstr_export_all,
577 /** unexport - KMKCCEVALCORE. */
578 kKmkCcEvalInstr_unexport_all,
579 /** [local|override] undefine - KMKCCEVALVARIABLES. */
580 kKmkCcEvalInstr_undefine,
581
582 /** [else] ifdef variable - KMKCCEVALIFDEFPLAIN. */
583 kKmkCcEvalInstr_ifdef_plain,
584 /** [else] ifndef variable - KMKCCEVALIFDEFPLAIN. */
585 kKmkCcEvalInstr_ifndef_plain,
586 /** [else] ifdef variable - KMKCCEVALIFDEFDYNAMIC. */
587 kKmkCcEvalInstr_ifdef_dynamic,
588 /** [else] ifndef variable - KMKCCEVALIFDEFDYNAMIC. */
589 kKmkCcEvalInstr_ifndef_dynamic,
590 /** [else] ifeq (a,b) - KMKCCEVALIFEQ. */
591 kKmkCcEvalInstr_ifeq,
592 /** [else] ifeq (a,b) - KMKCCEVALIFEQ. */
593 kKmkCcEvalInstr_ifneq,
594 /** [else] if1of (set-a,set-b) - KMKCCEVALIF1OF. */
595 kKmkCcEvalInstr_if1of,
596 /** [else] ifn1of (set-a,set-b) - KMKCCEVALIF1OF. */
597 kKmkCcEvalInstr_ifn1of,
598 /** [else] if expr - KMKCCEVALIFEXPR. */
599 kKmkCcEvalInstr_if,
600
601 /** include file1 [file2...] - KMKCCEVALINCLUDE. */
602 kKmkCcEvalInstr_include,
603 /** [sinclude|-include] file1 [file2...] - KMKCCEVALINCLUDE. */
604 kKmkCcEvalInstr_include_silent,
605 /** includedep file1 [file2...] - KMKCCEVALINCLUDE. */
606 kKmkCcEvalInstr_includedep,
607 /** includedep-queue file1 [file2...] - KMKCCEVALINCLUDE. */
608 kKmkCcEvalInstr_includedep_queue,
609 /** includedep-flush file1 [file2...] - KMKCCEVALINCLUDE. */
610 kKmkCcEvalInstr_includedep_flush,
611
612 /** Recipe without commands (defines dependencies) - KMKCCEVALRECIPE. */
613 kKmkCcEvalInstr_recipe_no_commands,
614 /** Recipe with commands (defines dependencies) - KMKCCEVALRECIPE. */
615 kKmkCcEvalInstr_recipe_start_normal,
616 /** Recipe with commands (defines dependencies) - KMKCCEVALRECIPE. */
617 kKmkCcEvalInstr_recipe_start_double_colon,
618 /** Recipe with commands (defines dependencies) - KMKCCEVALRECIPE. */
619 kKmkCcEvalInstr_recipe_start_pattern,
620 /** Adds more commands to the current recipe - KMKCCEVALRECIPECOMMANDS. */
621 kKmkCcEvalInstr_recipe_commands,
622 /** Special instruction for indicating the end of the recipe commands - KMKCCEVALCORE. */
623 kKmkCcEvalInstr_recipe_end,
624 /** Cancel previously defined pattern rule - KMKCCEVALRECIPE. */
625 kKmkCcEvalInstr_recipe_cancel_pattern,
626
627/** @todo target variables. */
628
629 /** vpath pattern directories - KMKCCEVALVPATH. */
630 kKmkCcEvalInstr_vpath,
631 /** vpath pattern directories - KMKCCEVALVPATH. */
632 kKmkCcEvalInstr_vpath_clear_pattern,
633 /** vpath - KMKCCEVALCORE. */
634 kKmkCcEvalInstr_vpath_clear_all,
635
636 /** Make 'code' needing expanding and evaluation - KMKCCEVALEXPAND.
637 * @note That this could in theory be used to start a recipe. This will be
638 * detected by the interpreter and loading will for now fail. A
639 * strategy for implement support for it would require picking up
640 * potential commands following the statements too. */
641 kKmkCcEvalInstr_expand,
642
643 /** The end of valid instructions (exclusive). */
644 kKmkCcEvalInstr_End
645} KMKCCEVALINSTR;
646
647/**
648 * Instruction core common to all instructions.
649 */
650typedef struct kmk_cc_eval_core
651{
652 /** The instruction opcode number (KMKCCEVALINSTR). */
653 KMKCCEVALINSTR enmOpcode;
654 /** The line number in the source this statement is associated with. */
655 unsigned iLine;
656} KMKCCEVALCORE;
657/** Pointer to an instruction core structure. */
658typedef KMKCCEVALCORE *PKMKCCEVALCORE;
659
660/**
661 * Instruction format for kKmkCcEvalInstr_jump.
662 */
663typedef struct kmk_cc_eval_jump
664{
665 /** The core instruction. */
666 KMKCCEVALCORE Core;
667 /** Where to jump to (new instruction block or endif, typically). */
668 PKMKCCEVALCORE pNext;
669} KMKCCEVALJUMP;
670typedef KMKCCEVALJUMP *PKMKCCEVALJUMP;
671
672/**
673 * Instruction format for kKmkCcEvalInstr_assign_recursive,
674 * kKmkCcEvalInstr_assign_simple, kKmkCcEvalInstr_assign_append,
675 * kKmkCcEvalInstr_assign_prepend and kKmkCcEvalInstr_assign_if_new.
676 */
677typedef struct kmk_cc_eval_assign
678{
679 /** The core instruction. */
680 KMKCCEVALCORE Core;
681 /** Whether the 'export' qualifier was used. */
682 uint8_t fExport;
683 /** Whether the 'override' qualifier was used. */
684 uint8_t fOverride;
685 /** Whether the 'local' qualifier was used. */
686 uint8_t fLocal;
687 /** Whether the 'private' qualifier was used. */
688 uint8_t fPrivate;
689 /** The variable name.
690 * @remarks Plain text names are in variable_strcache. */
691 KMKCCEXPSUBPROGORPLAIN Variable;
692 /** The value or value expression. */
693 KMKCCEXPSUBPROGORPLAIN Value;
694 /** Pointer to the next instruction. */
695 PKMKCCEVALCORE pNext;
696} KMKCCEVALASSIGN;
697typedef KMKCCEVALASSIGN *PKMKCCEVALASSIGN;
698
699/**
700 * Instruction format for kKmkCcEvalInstr_assign_define.
701 */
702typedef struct kmk_cc_eval_assign_define
703{
704 /** The assignment core structure. */
705 KMKCCEVALASSIGN AssignCore;
706 /** Makefile evaluation program compiled from the define.
707 * NULL if it does not compile.
708 * @todo Let's see if this is actually doable... */
709 PKMKCCEVALPROG pEvalProg;
710} KMKCCEVALASSIGNDEF;
711typedef KMKCCEVALASSIGNDEF *PKMKCCEVALASSIGNDEF;
712
713/**
714 * Instruction format for kKmkCcEvalInstr_export, kKmkCcEvalInstr_unexport and
715 * kKmkCcEvalInstr_undefine.
716 */
717typedef struct kmk_cc_eval_variables
718{
719 /** The core instruction. */
720 KMKCCEVALCORE Core;
721 /** The number of variables named in aVars. */
722 uint32_t cVars;
723 /** Whether the 'local' qualifier was used (undefine only). */
724 uint8_t fLocal;
725 /** Pointer to the next instruction. */
726 PKMKCCEVALCORE pNext;
727 /** The variable names.
728 * Expressions will be expanded and split on space.
729 * @remarks Plain text names are in variable_strcache. */
730 KMKCCEXPSUBPROGORPLAIN aVars[1];
731} KMKCCEVALVARIABLES;
732typedef KMKCCEVALVARIABLES *PKMKCCEVALVARIABLES;
733/** Calculates the size of an KMKCCEVALVARIABLES structure for @a a_cVars. */
734#define KMKCCEVALVARIABLES_SIZE(a_cVars) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALVARIABLES, aVars, a_cVars)
735
736/**
737 * Core structure for all conditionals (kKmkCcEvalInstr_if*).
738 */
739typedef struct kmk_cc_eval_if_core
740{
741 /** The core instruction. */
742 KMKCCEVALCORE Core;
743 /** Condition true: Pointer to the next instruction. */
744 PKMKCCEVALCORE pNextTrue;
745 /** Condition false: Pointer to the next instruction (i.e. 'else if*'
746 * or whatever follows 'else' / 'endif'. */
747 PKMKCCEVALCORE pNextFalse;
748 /** Pointer to the previous conditional for 'else if*' directives.
749 * This is only to assist the compilation process. */
750 struct kmk_cc_eval_if_core *pPrevCond;
751 /** Pointer to the jump out of the true block, if followed by 'else'.
752 * This is only to assist the compilation process. */
753 PKMKCCEVALJUMP pTrueEndJump;
754} KMKCCEVALIFCORE;
755typedef KMKCCEVALIFCORE *PKMKCCEVALIFCORE;
756
757/**
758 * Instruction format for kKmkCcEvalInstr_ifdef_plain and
759 * kKmkCcEvalInstr_ifndef_plain.
760 * The variable name is known at compilation time.
761 */
762typedef struct kmk_cc_eval_ifdef_plain
763{
764 /** The 'if' core structure. */
765 KMKCCEVALIFCORE IfCore;
766 /** The name of the variable (points into variable_strcache). */
767 const char *pszName;
768} KMKCCEVALIFDEFPLAIN;
769typedef KMKCCEVALIFDEFPLAIN *PKMKCCEVALIFDEFPLAIN;
770
771/**
772 * Instruction format for kKmkCcEvalInstr_ifdef_dynamic and
773 * kKmkCcEvalInstr_ifndef_dynamic.
774 * The variable name is dynamically expanded at run time.
775 */
776typedef struct kmk_cc_eval_ifdef_dynamic
777{
778 /** The 'if' core structure. */
779 KMKCCEVALIFCORE IfCore;
780 /** Alignment padding, MBZ. */
781 KU32 uPadding;
782 /** The subprogram that will give us the variable name. */
783 KMKCCEXPSUBPROG NameSubprog;
784} KMKCCEVALIFDEFDYNAMIC;
785typedef KMKCCEVALIFDEFDYNAMIC *PKMKCCEVALIFDEFDYNAMIC;
786
787/**
788 * Instruction format for kKmkCcEvalInstr_ifeq and kKmkCcEvalInstr_ifneq.
789 */
790typedef struct kmk_cc_eval_ifeq
791{
792 /** The 'if' core structure. */
793 KMKCCEVALIFCORE IfCore;
794 /** The left hand side string expression (dynamic or plain). */
795 KMKCCEXPSUBPROGORPLAIN Left;
796 /** The rigth hand side string expression (dynamic or plain). */
797 KMKCCEXPSUBPROGORPLAIN Right;
798} KMKCCEVALIFEQ;
799typedef KMKCCEVALIFEQ *PKMKCCEVALIFEQ;
800
801/**
802 * Instruction format for kKmkCcEvalInstr_if1of and kKmkCcEvalInstr_ifn1of.
803 *
804 * @todo This can be optimized further by pre-hashing plain text items. One of
805 * the sides are usually plain text.
806 */
807typedef struct kmk_cc_eval_if1of
808{
809 /** The 'if' core structure. */
810 KMKCCEVALIFCORE IfCore;
811 /** The left hand side string expression (dynamic or plain). */
812 KMKCCEXPSUBPROGORPLAIN Left;
813 /** The rigth hand side string expression (dynamic or plain). */
814 KMKCCEXPSUBPROGORPLAIN Right;
815} KMKCCEVALIF1OF;
816typedef KMKCCEVALIF1OF *PKMKCCEVALIF1OF;
817
818/**
819 * Instruction format for kKmkCcEvalInstr_if.
820 *
821 * @todo Parse and compile the expression. At least strip whitespace in it.
822 */
823typedef struct kmk_cc_eval_if_expr
824{
825 /** The 'if' core structure. */
826 KMKCCEVALIFCORE IfCore;
827 /** The expression string length. */
828 uint16_t cchExpr;
829 /** The expression string. */
830 char szExpr[1];
831} KMKCCEVALIFEXPR;
832typedef KMKCCEVALIFEXPR *PKMKCCEVALIFEXPR;
833/** Calculates the size of an KMKCCEVALIFEXPR structure for @a a_cchExpr long
834 * expression string (terminator is automatically added). */
835#define KMKCCEVALIFEXPR_SIZE(a_cchExpr) KMK_CC_BLOCK_ALIGN_SIZE(KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALIFEXPR, szExpr, (a_cchExpr) + 1))
836
837/**
838 * Instruction format for kKmkCcEvalInstr_include,
839 * kKmkCcEvalInstr_include_silent, kKmkCcEvalInstr_includedep,
840 * kKmkCcEvalInstr_includedep_queue, kKmkCcEvalInstr_includedep_flush.
841 */
842typedef struct kmk_cc_eval_include
843{
844 /** The core instruction. */
845 KMKCCEVALCORE Core;
846 /** The number of files. */
847 uint32_t cFiles;
848 /** Pointer to the next instruction (subprogs and strings after this one). */
849 PKMKCCEVALCORE pNext;
850 /** The files to be included.
851 * Expressions will be expanded and split on space.
852 * @todo Plain text file name could be replaced by file string cache entries. */
853 KMKCCEXPSUBPROGORPLAIN aFiles[1];
854} KMKCCEVALINCLUDE;
855typedef KMKCCEVALINCLUDE *PKMKCCEVALINCLUDE;
856/** Calculates the size of an KMKCCEVALINCLUDE structure for @a a_cFiles files. */
857#define KMKCCEVALINCLUDE_SIZE(a_cFiles) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALINCLUDE, aFiles, a_cFiles)
858
859/**
860 * Instruction format for kKmkCcEvalInstr_recipe_no_commands,
861 * kKmkCcEvalInstr_recipe_start_normal,
862 * kKmkCcEvalInstr_recipe_start_double_colon, kKmkCcEvalInstr_includedep_queue,
863 * kKmkCcEvalInstr_recipe_start_pattern.
864 */
865typedef struct kmk_cc_eval_recipe
866{
867 /** The core instruction. */
868 KMKCCEVALCORE Core;
869 /** The total number of files and dependencies in aFilesAndDeps. */
870 uint16_t cFilesAndDeps;
871
872 /** Number of targets (from index 0).
873 * This is always 1 if this is an explicit multitarget or pattern recipe,
874 * indicating the main target. */
875 uint16_t cTargets;
876 /** Explicit multitarget & patterns: First always made target. */
877 uint16_t iFirstAlwaysMadeTargets;
878 /** Explicit multitarget & patterns: Number of always targets. */
879 uint16_t cAlwaysMadeTargets;
880 /** Explicit multitarget: First maybe made target. */
881 uint16_t iFirstMaybeTarget;
882 /** Explicit multitarget: Number of maybe made targets. */
883 uint16_t cMaybeTargets;
884
885 /** First dependency. */
886 uint16_t iFirstDep;
887 /** Number of ordinary dependencies. */
888 uint16_t cDeps;
889 /** First order only dependency. */
890 uint16_t iFirstOrderOnlyDep;
891 /** Number of ordinary dependencies. */
892 uint16_t cOrderOnlyDeps;
893
894 /** Pointer to the next instruction (subprogs and strings after this one). */
895 PKMKCCEVALCORE pNext;
896 /** The .MUST_MAKE variable value, if present.
897 * If not present, this is a zero length plain string. */
898 KMKCCEXPSUBPROGORPLAIN MustMake;
899 /** The target files and dependencies.
900 * This is sorted into several sections, as defined by the above indexes and
901 * counts. Expressions will be expanded and split on space.
902 *
903 * The KMKCCEXPSUBPROGORPLAIN::bUser member one of KMKCCEVALRECIPE_FD_XXX.
904 *
905 * @todo Plain text file name could be replaced by file string cache entries. */
906 KMKCCEXPSUBPROGORPLAIN aFilesAndDeps[1];
907} KMKCCEVALRECIPE;
908typedef KMKCCEVALRECIPE *PKMKCCEVALRECIPE;
909/** Calculates the size of an KMKCCEVALRECIPE structure for @a a_cFiles
910 * files. */
911#define KMKCCEVALRECIPE_SIZE(a_cFilesAndDeps) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALRECIPE, aFilesAndDeps, a_cFilesAndDeps)
912/** @name KMKCCEVALRECIPE_FD_XXX - Values for KMKCCEVALRECIPE::aFilesAndDeps[x].bUser
913 * @{ */
914#define KMKCCEVALRECIPE_FD_NORMAL 0
915#define KMKCCEVALRECIPE_FD_SEC_EXP 1
916#define KMKCCEVALRECIPE_FD_SPECIAL_POSIX 2
917#define KMKCCEVALRECIPE_FD_SPECIAL_SECONDEXPANSION 3
918#define KMKCCEVALRECIPE_FD_SPECIAL_ONESHELL 4
919/** @} */
920
921
922/**
923 * Instruction format for kKmkCcEvalInstr_recipe_commands.
924 */
925typedef struct kmk_cc_eval_recipe_commands
926{
927 /** The core instruction. */
928 KMKCCEVALCORE Core;
929 /** The number of commands. */
930 uint32_t cCommands;
931 /** Pointer to the next instruction (subprogs and strings after this one). */
932 PKMKCCEVALCORE pNext;
933 /** Commands to add to the current recipe.
934 * Expressions will be expanded and split on newline? */
935 KMKCCEXPSUBPROGORPLAIN aCommands[1];
936} KMKCCEVALRECIPECOMMANDS;
937typedef KMKCCEVALRECIPECOMMANDS *PKMKCCEVALRECIPECOMMANDS;
938/** Calculates the size of an KMKCCEVALRECIPECOMMANDS structure for
939 * @a a_cCommands commands. */
940#define KMKCCEVALRECIPECOMMANDS_SIZE(a_cCommands) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALRECIPECOMMANDS, aCommands, a_cCommands)
941
942/**
943 * Instruction format for kKmkCcEvalInstr_vpath and
944 * kKmkCcEvalInstr_vpath_clear_pattern.
945 */
946typedef struct kmk_cc_eval_vpath
947{
948 /** The core instruction. */
949 KMKCCEVALCORE Core;
950 /** The number of search directories.
951 * This will be zero for kKmkCcEvalInstr_vpath_clear_pattern. */
952 uint32_t cDirs;
953 /** Pointer to the next instruction (subprogs and strings after this one). */
954 PKMKCCEVALCORE pNext;
955 /** The pattern. */
956 KMKCCEXPSUBPROGORPLAIN Pattern;
957 /** The directory. Expressions will be expanded and split on space. */
958 KMKCCEXPSUBPROGORPLAIN aDirs[1];
959} KMKCCEVALVPATH;
960typedef KMKCCEVALVPATH *PKMKCCEVALVPATH;
961/** Calculates the size of an KMKCCEVALVPATH structure for @a a_cFiles files. */
962#define KMKCCEVALVPATH_SIZE(a_cFiles) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALVPATH, aDirs, a_cDirs)
963
964
965/**
966 * Instruction format for kKmkCcEvalInstr_expand.
967 */
968typedef struct kmk_cc_eval_expand
969{
970 /** The core instruction. */
971 KMKCCEVALCORE Core;
972 /** Alignment padding, MBZ. */
973 KU32 uPadding;
974 /** The expansion subprogram that to execute and evaluate the output of. */
975 KMKCCEXPSUBPROG Subprog;
976} KMKCCEVALEXPAND;
977typedef KMKCCEVALEXPAND *PKMKCCEVALEXPAND;
978
979
980/**
981 * Makefile evaluation program.
982 */
983typedef struct kmk_cc_evalprog
984{
985 /** Pointer to the first instruction for this program. */
986 PKMKCCEVALCORE pFirstInstr;
987 /** List of blocks for this program (LIFO). */
988 PKMKCCBLOCK pBlockTail;
989 /** The name of the file containing this program. */
990 const char *pszFilename;
991 /** The name of the variable containing this program, if applicable. */
992 const char *pszVarName;
993#ifdef KMK_CC_STRICT
994 /** The hash of the input string. Used to check that we get all the change
995 * notifications we require. */
996 uint32_t uInputHash;
997#endif
998 /** Reference count. */
999 uint32_t volatile cRefs;
1000} KMKCCEVALPROG;
1001typedef KMKCCEVALPROG *PKMKCCEVALPROG;
1002
1003/** @} */
1004
1005
1006/*********************************************************************************************************************************
1007* Global Variables *
1008*********************************************************************************************************************************/
1009static uint32_t g_cVarForExpandCompilations = 0;
1010static uint32_t g_cVarForExpandExecs = 0;
1011static uint32_t g_cVarForEvalCompilations = 0;
1012static uint32_t g_cVarForEvalExecs = 0;
1013static uint32_t g_cFileForEvalCompilations = 0;
1014static uint32_t g_cFileForEvalExecs = 0;
1015#ifdef KMK_CC_WITH_STATS
1016static uint32_t g_cBlockAllocated = 0;
1017static uint32_t g_cbAllocated = 0;
1018
1019static uint32_t g_cBlocksAllocatedExpProgs = 0;
1020static uint32_t g_cbAllocatedExpProgs = 0;
1021static uint32_t g_cSingleBlockExpProgs = 0;
1022static uint32_t g_cTwoBlockExpProgs = 0;
1023static uint32_t g_cMultiBlockExpProgs = 0;
1024static uint32_t g_cbUnusedMemExpProgs = 0;
1025
1026static uint32_t g_cBlocksAllocatedEvalProgs = 0;
1027static uint32_t g_cbAllocatedEvalProgs = 0;
1028static uint32_t g_cSingleBlockEvalProgs = 0;
1029static uint32_t g_cTwoBlockEvalProgs = 0;
1030static uint32_t g_cMultiBlockEvalProgs = 0;
1031static uint32_t g_cbUnusedMemEvalProgs = 0;
1032
1033#endif
1034
1035/** Generic character classification, taking an 'unsigned char' index.
1036 * ASSUMES unsigned char is 8-bits. */
1037static uint16_t g_abEvalCcChars[256];
1038
1039
1040/**
1041 * Makefile evaluation keywords.
1042 */
1043static const char * const g_apszEvalKeywords[] =
1044{
1045 "define",
1046 "export",
1047 "else",
1048 "endef",
1049 "endif",
1050 "ifdef",
1051 "ifndef",
1052 "ifeq",
1053 "ifneq",
1054 "if1of",
1055 "ifn1of",
1056 "if",
1057 "include",
1058 "includedep",
1059 "includedep-queue",
1060 "includedep-flush",
1061 "local",
1062 "override",
1063 "private",
1064 "sinclude",
1065 "unexport",
1066 "undefine",
1067 "vpath",
1068 "-include",
1069};
1070
1071
1072/** This is parallel to KMKCCEVALINSTR. */
1073static const char * const g_apszEvalInstrNms[] =
1074{
1075 "jump",
1076 "assign_recursive",
1077 "assign_simple",
1078 "assign_append",
1079 "assign_prepend",
1080 "assign_if_new",
1081 "assign_define",
1082 "export",
1083 "unexport",
1084 "export_all",
1085 "unexport_all",
1086 "undefine",
1087 "ifdef_plain",
1088 "ifndef_plain",
1089 "ifdef_dynamic",
1090 "ifndef_dynamic",
1091 "ifeq",
1092 "ifneq",
1093 "if1of",
1094 "ifn1of",
1095 "if",
1096 "include",
1097 "include_silent",
1098 "includedep",
1099 "includedep_queue",
1100 "includedep_flush",
1101 "recipe_no_commands",
1102 "recipe_start_normal",
1103 "recipe_start_double_colon",
1104 "recipe_start_pattern",
1105 "recipe_commands",
1106 "recipe_end",
1107 "recipe_cancel_pattern",
1108 "vpath",
1109 "vpath_clear_pattern",
1110 "vpath_clear_all",
1111};
1112
1113/*********************************************************************************************************************************
1114* Internal Functions *
1115*********************************************************************************************************************************/
1116static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubprog);
1117static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubprog, uint32_t *pcch);
1118
1119
1120/**
1121 * Initializes global variables for the 'compiler'.
1122 */
1123void kmk_cc_init(void)
1124{
1125 unsigned i;
1126
1127 /*
1128 * Initialize the bitmap.
1129 */
1130 memset(g_abEvalCcChars, 0, sizeof(g_abEvalCcChars));
1131
1132 /* blank chars */
1133 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ' ', KMK_CC_EVAL_CH_BLANK);
1134 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\t', KMK_CC_EVAL_CH_BLANK);
1135
1136 /* space chars and zero terminator. */
1137#define MY_SPACE_BITS KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE
1138 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ' ', MY_SPACE_BITS);
1139 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\t', MY_SPACE_BITS);
1140 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\n', MY_SPACE_BITS | KMK_CC_EVAL_CH_EOL_CANDIDATE);
1141 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\v', MY_SPACE_BITS);
1142 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\f', MY_SPACE_BITS);
1143 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\r', MY_SPACE_BITS | KMK_CC_EVAL_CH_EOL_CANDIDATE);
1144 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE);
1145#undef MY_SPACE_BITS
1146
1147 /* keywords */
1148 for (i = 0; i < K_ELEMENTS(g_apszEvalKeywords); i++)
1149 {
1150#ifdef KMK_CC_STRICT
1151 size_t cch = strlen(g_apszEvalKeywords[i]);
1152 KMK_CC_ASSERT(cch >= KMK_CC_EVAL_KEYWORD_MIN);
1153 KMK_CC_ASSERT(cch <= KMK_CC_EVAL_KEYWORD_MAX);
1154#endif
1155
1156 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, g_apszEvalKeywords[i][0], KMK_CC_EVAL_CH_1ST_IN_KEYWORD);
1157 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, g_apszEvalKeywords[i][1], KMK_CC_EVAL_CH_2ND_IN_KEYWORD);
1158 }
1159 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'd', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* define */
1160 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'e', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* export (, endef) */
1161 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'l', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* local */
1162 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'o', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* override */
1163 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'p', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* private */
1164 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'u', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* undefine, unexport */
1165
1166 /* Assignment punctuation and recipe stuff. */
1167 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '=', KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE);
1168 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ':', KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE);
1169
1170 /* For locating the end of variable expansion. */
1171 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '(', KMK_CC_EVAL_CH_PAREN_OR_SLASH);
1172 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ')', KMK_CC_EVAL_CH_PAREN_OR_SLASH);
1173 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '{', KMK_CC_EVAL_CH_PAREN_OR_SLASH);
1174 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '}', KMK_CC_EVAL_CH_PAREN_OR_SLASH);
1175 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_PAREN_OR_SLASH);
1176
1177 /* For parsing ifeq and if1of expressions. (GNU weirdly does not respect {} style function references.) */
1178 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '(', KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR);
1179 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ')', KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR);
1180 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ',', KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR);
1181 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '$', KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR);
1182
1183 /* Misc. */
1184 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '$', KMK_CC_EVAL_CH_DOLLAR);
1185 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_BACKSLASH);
1186
1187 /*
1188 * Check that the eval instruction names match up.
1189 */
1190 KMK_CC_ASSERT(strcmp(g_apszEvalInstrNms[kKmkCcEvalInstr_ifneq], "ifneq") == 0);
1191 KMK_CC_ASSERT(strcmp(g_apszEvalInstrNms[kKmkCcEvalInstr_vpath_clear_all], "vpath_clear_all") == 0);
1192}
1193
1194
1195/**
1196 * Prints stats (for kmk -p).
1197 */
1198void kmk_cc_print_stats(void)
1199{
1200#ifdef KMK_CC_WITH_STATS
1201 uint32_t const cEvalCompilations = g_cFileForEvalCompilations + g_cVarForEvalCompilations;
1202#endif
1203
1204 puts(_("\n# The kmk 'compiler' and kmk 'program executor':\n"));
1205
1206 printf(_("# Variables compiled for string expansion: %6u\n"), g_cVarForExpandCompilations);
1207 printf(_("# Variables string expansion runs: %6u\n"), g_cVarForExpandExecs);
1208 printf(_("# String expansion runs per compile: %6u\n"), g_cVarForExpandExecs / g_cVarForExpandCompilations);
1209#ifdef KMK_CC_WITH_STATS
1210 printf(_("# Single alloc block exp progs: %6u (%u%%)\n"
1211 "# Two alloc block exp progs: %6u (%u%%)\n"
1212 "# Three or more alloc block exp progs: %6u (%u%%)\n"
1213 ),
1214 g_cSingleBlockExpProgs, (uint32_t)((uint64_t)g_cSingleBlockExpProgs * 100 / g_cVarForExpandCompilations),
1215 g_cTwoBlockExpProgs, (uint32_t)((uint64_t)g_cTwoBlockExpProgs * 100 / g_cVarForExpandCompilations),
1216 g_cMultiBlockExpProgs, (uint32_t)((uint64_t)g_cMultiBlockExpProgs * 100 / g_cVarForExpandCompilations));
1217 printf(_("# Total amount of memory for exp progs: %8u bytes\n"
1218 "# in: %6u blocks\n"
1219 "# avg block size: %6u bytes\n"
1220 "# unused memory: %8u bytes (%u%%)\n"
1221 "# avg unused memory per block: %6u bytes\n"
1222 "\n"),
1223 g_cbAllocatedExpProgs, g_cBlocksAllocatedExpProgs, g_cbAllocatedExpProgs / g_cBlocksAllocatedExpProgs,
1224 g_cbUnusedMemExpProgs, (uint32_t)((uint64_t)g_cbUnusedMemExpProgs * 100 / g_cbAllocatedExpProgs),
1225 g_cbUnusedMemExpProgs / g_cBlocksAllocatedExpProgs);
1226 puts("");
1227#endif
1228 printf(_("# Variables compiled for string eval: %6u\n"), g_cVarForEvalCompilations);
1229 printf(_("# Variables string eval runs: %6u\n"), g_cVarForEvalExecs);
1230 printf(_("# String evals runs per compile: %6u\n"), g_cVarForEvalExecs / g_cVarForEvalCompilations);
1231 printf(_("# Files compiled: %6u\n"), g_cFileForEvalCompilations);
1232 printf(_("# Files runs: %6u\n"), g_cFileForEvalExecs);
1233 printf(_("# Files eval runs per compile: %6u\n"), g_cFileForEvalExecs / g_cFileForEvalCompilations);
1234#ifdef KMK_CC_WITH_STATS
1235 printf(_("# Single alloc block eval progs: %6u (%u%%)\n"
1236 "# Two alloc block eval progs: %6u (%u%%)\n"
1237 "# Three or more alloc block eval progs: %6u (%u%%)\n"
1238 ),
1239 g_cSingleBlockEvalProgs, (uint32_t)((uint64_t)g_cSingleBlockEvalProgs * 100 / cEvalCompilations),
1240 g_cTwoBlockEvalProgs, (uint32_t)((uint64_t)g_cTwoBlockEvalProgs * 100 / cEvalCompilations),
1241 g_cMultiBlockEvalProgs, (uint32_t)((uint64_t)g_cMultiBlockEvalProgs * 100 / cEvalCompilations));
1242 printf(_("# Total amount of memory for eval progs: %8u bytes\n"
1243 "# in: %6u blocks\n"
1244 "# avg block size: %6u bytes\n"
1245 "# unused memory: %8u bytes (%u%%)\n"
1246 "# avg unused memory per block: %6u bytes\n"
1247 "\n"),
1248 g_cbAllocatedEvalProgs, g_cBlocksAllocatedEvalProgs, g_cbAllocatedEvalProgs / g_cBlocksAllocatedEvalProgs,
1249 g_cbUnusedMemEvalProgs, (uint32_t)((uint64_t)g_cbUnusedMemEvalProgs * 100 / g_cbAllocatedEvalProgs),
1250 g_cbUnusedMemEvalProgs / g_cBlocksAllocatedEvalProgs);
1251 puts("");
1252 printf(_("# Total amount of block mem allocated: %8u bytes\n"), g_cbAllocated);
1253 printf(_("# Total number of block allocated: %8u\n"), g_cBlockAllocated);
1254 printf(_("# Average block size: %8u byte\n"), g_cbAllocated / g_cBlockAllocated);
1255#endif
1256
1257 puts("");
1258}
1259
1260
1261/*
1262 *
1263 * Various utility functions.
1264 * Various utility functions.
1265 * Various utility functions.
1266 *
1267 */
1268
1269/**
1270 * Counts the number of dollar chars in the string.
1271 *
1272 * @returns Number of dollar chars.
1273 * @param pchStr The string to search (does not need to be zero
1274 * terminated).
1275 * @param cchStr The length of the string.
1276 */
1277static uint32_t kmk_cc_count_dollars(const char *pchStr, uint32_t cchStr)
1278{
1279 uint32_t cDollars = 0;
1280 const char *pch;
1281 while ((pch = memchr(pchStr, '$', cchStr)) != NULL)
1282 {
1283 cDollars++;
1284 cchStr -= pch - pchStr + 1;
1285 pchStr = pch + 1;
1286 }
1287 return cDollars;
1288}
1289
1290#ifdef KMK_CC_STRICT
1291/**
1292 * Used to check that function arguments are left alone.
1293 * @returns Updated hash.
1294 * @param uHash The current hash value.
1295 * @param psz The string to hash.
1296 */
1297static uint32_t kmk_cc_debug_string_hash(uint32_t uHash, const char *psz)
1298{
1299 unsigned char ch;
1300 while ((ch = *(unsigned char const *)psz++) != '\0')
1301 uHash = (uHash << 6) + (uHash << 16) - uHash + (unsigned char)ch;
1302 return uHash;
1303}
1304
1305/**
1306 * Used to check that function arguments are left alone.
1307 * @returns Updated hash.
1308 * @param uHash The current hash value.
1309 * @param pch The string to hash, not terminated.
1310 * @param cch The number of chars to hash.
1311 */
1312static uint32_t kmk_cc_debug_string_hash_n(uint32_t uHash, const char *pch, uint32_t cch)
1313{
1314 while (cch-- > 0)
1315 {
1316 unsigned char ch = *(unsigned char const *)pch++;
1317 uHash = (uHash << 6) + (uHash << 16) - uHash + (unsigned char)ch;
1318 }
1319 return uHash;
1320}
1321
1322#endif
1323
1324
1325
1326/*
1327 *
1328 * The allocator.
1329 * The allocator.
1330 * The allocator.
1331 *
1332 */
1333
1334
1335/**
1336 * For the first allocation using the block allocator.
1337 *
1338 * @returns Pointer to the first allocation (@a cbFirst in size).
1339 * @param ppBlockTail Where to return the pointer to the first block.
1340 * @param cbFirst The size of the first allocation.
1341 * @param cbHint Hint about how much memory we might be needing.
1342 */
1343static void *kmk_cc_block_alloc_first(PKMKCCBLOCK *ppBlockTail, size_t cbFirst, size_t cbHint)
1344{
1345 uint32_t cbBlock;
1346 PKMKCCBLOCK pNewBlock;
1347
1348 KMK_CC_ASSERT_ALIGNED(cbFirst, sizeof(void *));
1349 KMK_CC_ASSERT(cbFirst <= 128);
1350
1351 /*
1352 * Turn the hint into a block size.
1353 */
1354 cbHint += cbFirst;
1355 if (cbHint <= 512)
1356 {
1357 if (cbHint <= 256)
1358 {
1359 if (cbFirst <= 64)
1360 cbBlock = 128;
1361 else
1362 cbBlock = 256;
1363 }
1364 else
1365 cbBlock = 256;
1366 }
1367 else if (cbHint < 2048)
1368 cbBlock = 1024;
1369 else if (cbHint < 3072)
1370 cbBlock = 2048;
1371 else
1372 cbBlock = 4096;
1373
1374 /*
1375 * Allocate and initialize the first block.
1376 */
1377 pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
1378 pNewBlock->cbBlock = cbBlock;
1379 pNewBlock->offNext = sizeof(*pNewBlock) + cbFirst;
1380 pNewBlock->pNext = NULL;
1381 *ppBlockTail = pNewBlock;
1382
1383#ifdef KMK_CC_WITH_STATS
1384 g_cBlockAllocated++;
1385 g_cbAllocated += cbBlock;
1386#endif
1387
1388 return pNewBlock + 1;
1389}
1390
1391
1392/**
1393 * Used for getting the address of the next instruction.
1394 *
1395 * @returns Pointer to the next allocation.
1396 * @param pBlockTail The allocator tail pointer.
1397 */
1398static void *kmk_cc_block_get_next_ptr(PKMKCCBLOCK pBlockTail)
1399{
1400 return (char *)pBlockTail + pBlockTail->offNext;
1401}
1402
1403
1404/**
1405 * Realigns the allocator after doing byte or string allocations.
1406 *
1407 * @param ppBlockTail Pointer to the allocator tail pointer.
1408 */
1409static void kmk_cc_block_realign(PKMKCCBLOCK *ppBlockTail)
1410{
1411 PKMKCCBLOCK pBlockTail = *ppBlockTail;
1412 uint32_t offNext = pBlockTail->offNext;
1413 if (offNext & (sizeof(void *) - 1U))
1414 {
1415 pBlockTail->offNext = KMK_CC_BLOCK_ALIGN_SIZE(offNext);
1416 KMK_CC_BLOCK_DPRINTF(("kmk_cc_block_realign: offNext=%#x -> %#x\n", offNext, pBlockTail->offNext));
1417 KMK_CC_ASSERT(pBlockTail->cbBlock - pBlockTail->offNext >= sizeof(KMKCCEXPJUMP));
1418 }
1419}
1420
1421
1422/**
1423 * Grows the allocation with another block, byte allocator case.
1424 *
1425 * @returns Pointer to the byte allocation.
1426 * @param ppBlockTail Pointer to the allocator tail pointer.
1427 * @param cb The number of bytes to allocate.
1428 */
1429static void *kmk_cc_block_byte_alloc_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1430{
1431 PKMKCCBLOCK pOldBlock = *ppBlockTail;
1432 PKMKCCBLOCK pPrevBlock = pOldBlock->pNext;
1433 PKMKCCBLOCK pNewBlock;
1434 uint32_t cbBlock;
1435
1436 /*
1437 * Check if there accidentally is some space left in the previous block first.
1438 */
1439 if ( pPrevBlock
1440 && pPrevBlock->cbBlock - pPrevBlock->offNext >= cb)
1441 {
1442 void *pvRet = (char *)pPrevBlock + pPrevBlock->offNext;
1443 pPrevBlock->offNext += cb;
1444 KMK_CC_BLOCK_DPRINTF(("kmk_cc_block_byte_alloc_grow: %p LB %#x offNext=%#x [prev]\n", pvRet, cb, pPrevBlock->offNext));
1445 return pvRet;
1446 }
1447
1448 /*
1449 * Allocate a new block.
1450 */
1451
1452 /* Figure the block size. */
1453 cbBlock = pOldBlock->cbBlock;
1454 while (cbBlock - sizeof(KMKCCEXPJUMP) - sizeof(*pNewBlock) < cb)
1455 cbBlock *= 2;
1456
1457 /* Allocate and initialize the block it with the new instruction already accounted for. */
1458 pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
1459 pNewBlock->cbBlock = cbBlock;
1460 pNewBlock->offNext = sizeof(*pNewBlock) + cb;
1461 pNewBlock->pNext = pOldBlock;
1462 *ppBlockTail = pNewBlock;
1463
1464#ifdef KMK_CC_WITH_STATS
1465 g_cBlockAllocated++;
1466 g_cbAllocated += cbBlock;
1467#endif
1468
1469 KMK_CC_BLOCK_DPRINTF(("kmk_cc_block_byte_alloc_grow: %p LB %#x offNext=%#x\n", pNewBlock + 1, cb, pNewBlock->offNext));
1470 return pNewBlock + 1;
1471}
1472
1473
1474/**
1475 * Make a byte allocation.
1476 *
1477 * Must call kmk_cc_block_realign() when done doing byte and string allocations.
1478 *
1479 * @returns Pointer to the byte allocation (byte aligned).
1480 * @param ppBlockTail Pointer to the allocator tail pointer.
1481 * @param cb The number of bytes to allocate.
1482 */
1483static void *kmk_cc_block_byte_alloc(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1484{
1485 PKMKCCBLOCK pBlockTail = *ppBlockTail;
1486 uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;
1487
1488 KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEXPJUMP));
1489 if (cbLeft >= cb + sizeof(KMKCCEXPJUMP))
1490 {
1491 void *pvRet = (char *)pBlockTail + pBlockTail->offNext;
1492 pBlockTail->offNext += cb;
1493 KMK_CC_BLOCK_DPRINTF(("kmk_cc_block_byte_alloc: %p LB %#x offNext=%#x\n", pvRet, cb, pBlockTail->offNext));
1494 return pvRet;
1495 }
1496 return kmk_cc_block_byte_alloc_grow(ppBlockTail, cb);
1497}
1498
1499
1500/**
1501 * Duplicates the given string in a byte allocation.
1502 *
1503 * Must call kmk_cc_block_realign() when done doing byte and string allocations.
1504 *
1505 * @returns Pointer to the byte allocation (byte aligned).
1506 * @param ppBlockTail Pointer to the allocator tail pointer.
1507 * @param cb The number of bytes to allocate.
1508 */
1509static const char *kmk_cc_block_strdup(PKMKCCBLOCK *ppBlockTail, const char *pachStr, uint32_t cchStr)
1510{
1511 char *pszCopy;
1512 if (cchStr)
1513 {
1514 pszCopy = kmk_cc_block_byte_alloc(ppBlockTail, cchStr + 1);
1515 memcpy(pszCopy, pachStr, cchStr);
1516 pszCopy[cchStr] = '\0';
1517 return pszCopy;
1518 }
1519 return "";
1520}
1521
1522
1523/**
1524 * Grows the allocation with another block, string expansion program case.
1525 *
1526 * @returns Pointer to a string expansion instruction core.
1527 * @param ppBlockTail Pointer to the allocator tail pointer.
1528 * @param cb The number of bytes to allocate.
1529 */
1530static PKMKCCEXPCORE kmk_cc_block_alloc_exp_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1531{
1532 PKMKCCBLOCK pOldBlock = *ppBlockTail;
1533 PKMKCCBLOCK pNewBlock;
1534 PKMKCCEXPCORE pRet;
1535 PKMKCCEXPJUMP pJump;
1536
1537 /* Figure the block size. */
1538 uint32_t cbBlock = !pOldBlock->pNext ? 128 : pOldBlock->cbBlock;
1539 while (cbBlock - sizeof(KMKCCEXPJUMP) - sizeof(*pNewBlock) < cb)
1540 cbBlock *= 2;
1541
1542 /* Allocate and initialize the block it with the new instruction already accounted for. */
1543 pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
1544 pNewBlock->cbBlock = cbBlock;
1545 pNewBlock->offNext = sizeof(*pNewBlock) + cb;
1546 pNewBlock->pNext = pOldBlock;
1547 *ppBlockTail = pNewBlock;
1548
1549#ifdef KMK_CC_WITH_STATS
1550 g_cBlockAllocated++;
1551 g_cbAllocated += cbBlock;
1552#endif
1553
1554 pRet = (PKMKCCEXPCORE)(pNewBlock + 1);
1555 KMK_CC_ASSERT(((size_t)pRet & (sizeof(void *) - 1)) == 0);
1556
1557 /* Emit jump. */
1558 pJump = (PKMKCCEXPJUMP)((char *)pOldBlock + pOldBlock->offNext);
1559 pJump->Core.enmOpcode = kKmkCcExpInstr_Jump;
1560 pJump->pNext = pRet;
1561 pOldBlock->offNext += sizeof(*pJump);
1562 KMK_CC_ASSERT(pOldBlock->offNext <= pOldBlock->cbBlock);
1563
1564 KMK_CC_BLOCK_DPRINTF(("kmk_cc_block_alloc_exp_grow: %p LB %#x offNext=%#x\n", pRet, cb, pNewBlock->offNext));
1565 return pRet;
1566}
1567
1568
1569/**
1570 * Allocates a string expansion instruction of size @a cb.
1571 *
1572 * @returns Pointer to a string expansion instruction core.
1573 * @param ppBlockTail Pointer to the allocator tail pointer.
1574 * @param cb The number of bytes to allocate.
1575 */
1576static PKMKCCEXPCORE kmk_cc_block_alloc_exp(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1577{
1578 PKMKCCBLOCK pBlockTail = *ppBlockTail;
1579 uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;
1580
1581 KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEXPJUMP));
1582 KMK_CC_ASSERT( (cb & (sizeof(void *) - 1)) == 0 || cb == sizeof(KMKCCEXPCORE) /* final */ );
1583 KMK_CC_ASSERT((pBlockTail->offNext & (sizeof(void *) - 1)) == 0);
1584
1585 if (cbLeft >= cb + sizeof(KMKCCEXPJUMP))
1586 {
1587 PKMKCCEXPCORE pRet = (PKMKCCEXPCORE)((char *)pBlockTail + pBlockTail->offNext);
1588 pBlockTail->offNext += cb;
1589 KMK_CC_ASSERT(((size_t)pRet & (sizeof(void *) - 1)) == 0);
1590 KMK_CC_BLOCK_DPRINTF(("kmk_cc_block_alloc_exp: %p LB %#x offNext=%#x\n", pRet, cb, pBlockTail->offNext));
1591 return pRet;
1592 }
1593 return kmk_cc_block_alloc_exp_grow(ppBlockTail, cb);
1594}
1595
1596
1597/**
1598 * Grows the allocation with another block, makefile evaluation program case.
1599 *
1600 * @returns Pointer to a makefile evaluation instruction core.
1601 * @param ppBlockTail Pointer to the allocator tail pointer.
1602 * @param cb The number of bytes to allocate.
1603 */
1604static PKMKCCEVALCORE kmk_cc_block_alloc_eval_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1605{
1606 PKMKCCBLOCK pOldBlock = *ppBlockTail;
1607 PKMKCCBLOCK pNewBlock;
1608 PKMKCCEVALCORE pRet;
1609 PKMKCCEVALJUMP pJump;
1610
1611 /* Figure the block size. */
1612 uint32_t cbBlock = !pOldBlock->pNext ? 128 : pOldBlock->cbBlock;
1613 while (cbBlock - sizeof(KMKCCEVALJUMP) - sizeof(*pNewBlock) < cb)
1614 cbBlock *= 2;
1615
1616 /* Allocate and initialize the block it with the new instruction already accounted for. */
1617 pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
1618 pNewBlock->cbBlock = cbBlock;
1619 pNewBlock->offNext = sizeof(*pNewBlock) + cb;
1620 pNewBlock->pNext = pOldBlock;
1621 *ppBlockTail = pNewBlock;
1622
1623#ifdef KMK_CC_WITH_STATS
1624 g_cBlockAllocated++;
1625 g_cbAllocated += cbBlock;
1626#endif
1627
1628 pRet = (PKMKCCEVALCORE)(pNewBlock + 1);
1629
1630 /* Emit jump. */
1631 pJump = (PKMKCCEVALJUMP)((char *)pOldBlock + pOldBlock->offNext);
1632 pJump->Core.enmOpcode = kKmkCcEvalInstr_jump;
1633 pJump->pNext = pRet;
1634 pOldBlock->offNext += sizeof(*pJump);
1635 KMK_CC_ASSERT(pOldBlock->offNext <= pOldBlock->cbBlock);
1636 KMK_CC_ASSERT((pNewBlock->offNext & (sizeof(void *) - 1)) == 0);
1637
1638 KMK_CC_BLOCK_DPRINTF(("kmk_cc_block_alloc_eval_grow: %p LB %#x offNext=%#x (*ppBlockTail=%p, was %p)\n",
1639 pRet, cb, pNewBlock->offNext, *ppBlockTail, pOldBlock));
1640 return pRet;
1641}
1642
1643
1644/**
1645 * Allocates a makefile evaluation instruction of size @a cb.
1646 *
1647 * @returns Pointer to a makefile evaluation instruction core.
1648 * @param ppBlockTail Pointer to the allocator tail pointer.
1649 * @param cb The number of bytes to allocate.
1650 */
1651static PKMKCCEVALCORE kmk_cc_block_alloc_eval(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1652{
1653 PKMKCCBLOCK pBlockTail = *ppBlockTail;
1654 uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;
1655
1656 KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEVALJUMP));
1657 KMK_CC_ASSERT( (cb & (sizeof(void *) - 1)) == 0 );
1658 KMK_CC_ASSERT((pBlockTail->offNext & (sizeof(void *) - 1)) == 0);
1659
1660 if (cbLeft >= cb + sizeof(KMKCCEVALJUMP))
1661 {
1662 PKMKCCEVALCORE pRet = (PKMKCCEVALCORE)((char *)pBlockTail + pBlockTail->offNext);
1663 pBlockTail->offNext += cb;
1664 KMK_CC_BLOCK_DPRINTF(("kmk_cc_block_alloc_eval: %p LB %#x offNext=%#x\n", pRet, cb, pBlockTail->offNext));
1665 return pRet;
1666 }
1667 return kmk_cc_block_alloc_eval_grow(ppBlockTail, cb);
1668}
1669
1670
1671/**
1672 * Frees all memory used by an allocator.
1673 *
1674 * @param ppBlockTail The allocator tail pointer.
1675 */
1676static void kmk_cc_block_free_list(PKMKCCBLOCK pBlockTail)
1677{
1678 while (pBlockTail)
1679 {
1680 PKMKCCBLOCK pThis = pBlockTail;
1681 pBlockTail = pBlockTail->pNext;
1682 free(pThis);
1683 }
1684}
1685
1686
1687/*
1688 *
1689 * The string expansion compiler.
1690 * The string expansion compiler.
1691 * The string expansion compiler.
1692 *
1693 */
1694
1695
1696/**
1697 * Emits a kKmkCcExpInstr_Return.
1698 *
1699 * @param ppBlockTail Pointer to the allocator tail pointer.
1700 */
1701static void kmk_cc_exp_emit_return(PKMKCCBLOCK *ppBlockTail)
1702{
1703 PKMKCCEXPCORE pCore = kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pCore));
1704 pCore->enmOpcode = kKmkCcExpInstr_Return;
1705 kmk_cc_block_realign(ppBlockTail);
1706}
1707
1708
1709/**
1710 * Checks if a function is known to mess up the arguments its given.
1711 *
1712 * When executing calls to "dirty" functions, all arguments must be duplicated
1713 * on the heap.
1714 *
1715 * @returns 1 if dirty, 0 if clean.
1716 * @param pszFunction The function name.
1717 */
1718static uint8_t kmk_cc_is_dirty_function(const char *pszFunction)
1719{
1720 switch (pszFunction[0])
1721 {
1722 default:
1723 return 0;
1724
1725 case 'e':
1726 if (!strcmp(pszFunction, "eval"))
1727 return 1;
1728 if (!strcmp(pszFunction, "evalctx"))
1729 return 1;
1730 return 0;
1731
1732 case 'f':
1733 if (!strcmp(pszFunction, "filter"))
1734 return 1;
1735 if (!strcmp(pszFunction, "filter-out"))
1736 return 1;
1737 if (!strcmp(pszFunction, "for"))
1738 return 1;
1739 return 0;
1740
1741 case 's':
1742 if (!strcmp(pszFunction, "sort"))
1743 return 1;
1744 return 0;
1745 }
1746}
1747
1748
1749/**
1750 * Emits a function call instruction taking arguments that needs expanding.
1751 *
1752 * @returns 0 on success, non-zero on failure.
1753 * @param ppBlockTail Pointer to the allocator tail pointer.
1754 * @param pszFunction The function name (const string from function.c).
1755 * @param pchArgs Pointer to the arguments expression string, leading
1756 * any blanks has been stripped.
1757 * @param cchArgs The length of the arguments expression string.
1758 * @param cArgs Number of arguments found.
1759 * @param chOpen The char used to open the function call.
1760 * @param chClose The char used to close the function call.
1761 * @param pfnFunction The function implementation.
1762 * @param cMaxArgs Maximum number of arguments the function takes.
1763 */
1764static int kmk_cc_exp_emit_dyn_function(PKMKCCBLOCK *ppBlockTail, const char *pszFunction,
1765 const char *pchArgs, uint32_t cchArgs, uint32_t cArgs, char chOpen, char chClose,
1766 make_function_ptr_t pfnFunction, unsigned char cMaxArgs)
1767{
1768 uint32_t iArg;
1769
1770 /*
1771 * The function instruction has variable size. The maximum argument count
1772 * isn't quite like the minium one. Zero means no limit. While a non-zero
1773 * value means that any commas beyond the max will be taken to be part of
1774 * the final argument.
1775 */
1776 uint32_t cActualArgs = cArgs <= cMaxArgs || !cMaxArgs ? cArgs : cMaxArgs;
1777 PKMKCCEXPDYNFUNC pInstr = (PKMKCCEXPDYNFUNC)kmk_cc_block_alloc_exp(ppBlockTail, KMKCCEXPDYNFUNC_SIZE(cActualArgs));
1778 pInstr->FnCore.Core.enmOpcode = kKmkCcExpInstr_DynamicFunction;
1779 pInstr->FnCore.cArgs = cActualArgs;
1780 pInstr->FnCore.pfnFunction = pfnFunction;
1781 pInstr->FnCore.pszFuncName = pszFunction;
1782 pInstr->FnCore.fDirty = kmk_cc_is_dirty_function(pszFunction);
1783
1784 /*
1785 * Parse the arguments. Plain arguments gets duplicated in the program
1786 * memory so that they are terminated and no extra processing is necessary
1787 * later on. ASSUMES that the function implementations do NOT change
1788 * argument memory. Other arguments the compiled into their own expansion
1789 * sub programs.
1790 */
1791 iArg = 0;
1792 for (;;)
1793 {
1794 /* Find the end of the argument. Check for $. */
1795 char ch = '\0';
1796 uint8_t fDollar = 0;
1797 int32_t cDepth = 0;
1798 uint32_t cchThisArg = 0;
1799 while (cchThisArg < cchArgs)
1800 {
1801 ch = pchArgs[cchThisArg];
1802 if (ch == chClose)
1803 {
1804 KMK_CC_ASSERT(cDepth > 0);
1805 if (cDepth > 0)
1806 cDepth--;
1807 }
1808 else if (ch == chOpen)
1809 cDepth++;
1810 else if (ch == ',' && cDepth == 0 && iArg + 1 < cActualArgs)
1811 break;
1812 else if (ch == '$')
1813 fDollar = 1;
1814 cchThisArg++;
1815 }
1816
1817 pInstr->aArgs[iArg].fSubprog = fDollar;
1818 if (fDollar)
1819 {
1820 /* Compile it. */
1821 int rc;
1822 kmk_cc_block_realign(ppBlockTail);
1823 rc = kmk_cc_exp_compile_subprog(ppBlockTail, pchArgs, cchThisArg, &pInstr->aArgs[iArg].u.Subprog);
1824 if (rc != 0)
1825 return rc;
1826 }
1827 else
1828 {
1829 /* Duplicate it. */
1830 pInstr->aArgs[iArg].u.Plain.psz = kmk_cc_block_strdup(ppBlockTail, pchArgs, cchThisArg);
1831 pInstr->aArgs[iArg].u.Plain.cch = cchThisArg;
1832 }
1833 iArg++;
1834 if (ch != ',')
1835 break;
1836 pchArgs += cchThisArg + 1;
1837 cchArgs -= cchThisArg + 1;
1838 }
1839 KMK_CC_ASSERT(iArg == cActualArgs);
1840
1841 /*
1842 * Realign the allocator and take down the address of the next instruction.
1843 */
1844 kmk_cc_block_realign(ppBlockTail);
1845 pInstr->FnCore.pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1846 return 0;
1847}
1848
1849
1850/**
1851 * Emits a function call instruction taking plain arguments.
1852 *
1853 * @returns 0 on success, non-zero on failure.
1854 * @param ppBlockTail Pointer to the allocator tail pointer.
1855 * @param pszFunction The function name (const string from function.c).
1856 * @param pchArgs Pointer to the arguments string, leading any blanks
1857 * has been stripped.
1858 * @param cchArgs The length of the arguments string.
1859 * @param cArgs Number of arguments found.
1860 * @param chOpen The char used to open the function call.
1861 * @param chClose The char used to close the function call.
1862 * @param pfnFunction The function implementation.
1863 * @param cMaxArgs Maximum number of arguments the function takes.
1864 */
1865static void kmk_cc_exp_emit_plain_function(PKMKCCBLOCK *ppBlockTail, const char *pszFunction,
1866 const char *pchArgs, uint32_t cchArgs, uint32_t cArgs, char chOpen, char chClose,
1867 make_function_ptr_t pfnFunction, unsigned char cMaxArgs)
1868{
1869 uint32_t iArg;
1870
1871 /*
1872 * The function instruction has variable size. The maximum argument count
1873 * isn't quite like the minium one. Zero means no limit. While a non-zero
1874 * value means that any commas beyond the max will be taken to be part of
1875 * the final argument.
1876 */
1877 uint32_t cActualArgs = cArgs <= cMaxArgs || !cMaxArgs ? cArgs : cMaxArgs;
1878 PKMKCCEXPPLAINFUNC pInstr = (PKMKCCEXPPLAINFUNC)kmk_cc_block_alloc_exp(ppBlockTail, KMKCCEXPPLAINFUNC_SIZE(cActualArgs));
1879 pInstr->FnCore.Core.enmOpcode = kKmkCcExpInstr_PlainFunction;
1880 pInstr->FnCore.cArgs = cActualArgs;
1881 pInstr->FnCore.pfnFunction = pfnFunction;
1882 pInstr->FnCore.pszFuncName = pszFunction;
1883 pInstr->FnCore.fDirty = kmk_cc_is_dirty_function(pszFunction);
1884
1885 /*
1886 * Parse the arguments. Plain arguments gets duplicated in the program
1887 * memory so that they are terminated and no extra processing is necessary
1888 * later on. ASSUMES that the function implementations do NOT change
1889 * argument memory.
1890 */
1891 iArg = 0;
1892 for (;;)
1893 {
1894 /* Find the end of the argument. */
1895 char ch = '\0';
1896 int32_t cDepth = 0;
1897 uint32_t cchThisArg = 0;
1898 while (cchThisArg < cchArgs)
1899 {
1900 ch = pchArgs[cchThisArg];
1901 if (ch == chClose)
1902 {
1903 KMK_CC_ASSERT(cDepth > 0);
1904 if (cDepth > 0)
1905 cDepth--;
1906 }
1907 else if (ch == chOpen)
1908 cDepth++;
1909 else if (ch == ',' && cDepth == 0 && iArg + 1 < cActualArgs)
1910 break;
1911 cchThisArg++;
1912 }
1913
1914 /* Duplicate it. */
1915 pInstr->apszArgs[iArg++] = kmk_cc_block_strdup(ppBlockTail, pchArgs, cchThisArg);
1916 if (ch != ',')
1917 break;
1918 pchArgs += cchThisArg + 1;
1919 cchArgs -= cchThisArg + 1;
1920 }
1921
1922 KMK_CC_ASSERT(iArg == cActualArgs);
1923 pInstr->apszArgs[iArg] = NULL;
1924
1925 /*
1926 * Realign the allocator and take down the address of the next instruction.
1927 */
1928 kmk_cc_block_realign(ppBlockTail);
1929 pInstr->FnCore.pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1930}
1931
1932
1933/**
1934 * Emits a kKmkCcExpInstr_DynamicVariable.
1935 *
1936 * @returns 0 on success, non-zero on failure.
1937 * @param ppBlockTail Pointer to the allocator tail pointer.
1938 * @param pchNameExpr The name of the variable (ASSUMED presistent
1939 * thru-out the program life time).
1940 * @param cchNameExpr The length of the variable name. If zero,
1941 * nothing will be emitted.
1942 */
1943static int kmk_cc_exp_emit_dyn_variable(PKMKCCBLOCK *ppBlockTail, const char *pchNameExpr, uint32_t cchNameExpr)
1944{
1945 PKMKCCEXPDYNVAR pInstr;
1946 int rc;
1947 KMK_CC_ASSERT(cchNameExpr > 0);
1948
1949 pInstr = (PKMKCCEXPDYNVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1950 pInstr->Core.enmOpcode = kKmkCcExpInstr_DynamicVariable;
1951
1952 rc = kmk_cc_exp_compile_subprog(ppBlockTail, pchNameExpr, cchNameExpr, &pInstr->Subprog);
1953
1954 pInstr->pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1955 return rc;
1956}
1957
1958
1959/**
1960 * Emits either a kKmkCcExpInstr_PlainVariable or
1961 * kKmkCcExpInstr_SearchAndReplacePlainVariable instruction.
1962 *
1963 * @param ppBlockTail Pointer to the allocator tail pointer.
1964 * @param pchName The name of the variable. (Does not need to be
1965 * valid beyond the call.)
1966 * @param cchName The length of the variable name. If zero,
1967 * nothing will be emitted.
1968 */
1969static void kmk_cc_exp_emit_plain_variable_maybe_sr(PKMKCCBLOCK *ppBlockTail, const char *pchName, uint32_t cchName)
1970{
1971 if (cchName > 0)
1972 {
1973 /*
1974 * Hopefully, we're not expected to do any search and replace on the
1975 * expanded variable string later... Requires both ':' and '='.
1976 */
1977 const char *pchEqual;
1978 const char *pchColon = (const char *)memchr(pchName, ':', cchName);
1979 if ( pchColon == NULL
1980 || (pchEqual = (const char *)memchr(pchColon + 1, ':', cchName - (pchColon - pchName - 1))) == NULL
1981 || pchEqual == pchEqual + 1)
1982 {
1983 PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1984 pInstr->Core.enmOpcode = kKmkCcExpInstr_PlainVariable;
1985 pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName);
1986 }
1987 else if (pchColon != pchName)
1988 {
1989 /*
1990 * Okay, we need to do search and replace the variable value.
1991 * This is performed by patsubst_expand_pat using '%' patterns.
1992 */
1993 uint32_t cchName2 = (uint32_t)(pchColon - pchName);
1994 uint32_t cchSearch = (uint32_t)(pchEqual - pchColon - 1);
1995 uint32_t cchReplace = cchName - cchName2 - cchSearch - 2;
1996 const char *pchPct;
1997 char *psz;
1998 PKMKCCEXPSRPLAINVAR pInstr;
1999
2000 pInstr = (PKMKCCEXPSRPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
2001 pInstr->Core.enmOpcode = kKmkCcExpInstr_SearchAndReplacePlainVariable;
2002 pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName2);
2003
2004 /* Figure out the search pattern, unquoting percent chars.. */
2005 psz = (char *)kmk_cc_block_byte_alloc(ppBlockTail, cchSearch + 2);
2006 psz[0] = '%';
2007 memcpy(psz + 1, pchColon + 1, cchSearch);
2008 psz[1 + cchSearch] = '\0';
2009 pchPct = find_percent(psz + 1); /* also performs unquoting */
2010 if (pchPct)
2011 {
2012 pInstr->pszSearchPattern = psz + 1;
2013 pInstr->offPctSearchPattern = (uint32_t)(pchPct - psz - 1);
2014 }
2015 else
2016 {
2017 pInstr->pszSearchPattern = psz;
2018 pInstr->offPctSearchPattern = 0;
2019 }
2020
2021 /* Figure out the replacement pattern, unquoting percent chars.. */
2022 if (cchReplace == 0)
2023 {
2024 pInstr->pszReplacePattern = "%";
2025 pInstr->offPctReplacePattern = 0;
2026 }
2027 else
2028 {
2029 psz = (char *)kmk_cc_block_byte_alloc(ppBlockTail, cchReplace + 2);
2030 psz[0] = '%';
2031 memcpy(psz + 1, pchEqual + 1, cchReplace);
2032 psz[1 + cchReplace] = '\0';
2033 pchPct = find_percent(psz + 1); /* also performs unquoting */
2034 if (pchPct)
2035 {
2036 pInstr->pszReplacePattern = psz + 1;
2037 pInstr->offPctReplacePattern = (uint32_t)(pchPct - psz - 1);
2038 }
2039 else
2040 {
2041 pInstr->pszReplacePattern = psz;
2042 pInstr->offPctReplacePattern = 0;
2043 }
2044 }
2045
2046 /* Note down where the next instruction is after realigning the allocator. */
2047 kmk_cc_block_realign(ppBlockTail);
2048 pInstr->pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
2049 }
2050 }
2051}
2052
2053
2054/**
2055 * Emits a kKmkCcExpInstr_CopyString.
2056 *
2057 * @param ppBlockTail Pointer to the allocator tail pointer.
2058 * @param pchStr The string to emit (ASSUMED presistent thru-out
2059 * the program life time).
2060 * @param cchStr The number of chars to copy. If zero, nothing
2061 * will be emitted.
2062 */
2063static void kmk_cc_exp_emit_copy_string(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr)
2064{
2065 if (cchStr > 0)
2066 {
2067 PKMKCCEXPCOPYSTRING pInstr = (PKMKCCEXPCOPYSTRING)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
2068 pInstr->Core.enmOpcode = kKmkCcExpInstr_CopyString;
2069 pInstr->cchCopy = cchStr;
2070 pInstr->pachSrc = pchStr;
2071 }
2072}
2073
2074
2075/**
2076 * String expansion compilation function common to both normal and sub programs.
2077 *
2078 * @returns 0 on success, non-zero on failure.
2079 * @param ppBlockTail Pointer to the allocator tail pointer.
2080 * @param pchStr The expression to compile.
2081 * @param cchStr The length of the expression to compile.
2082 */
2083static int kmk_cc_exp_compile_common(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr)
2084{
2085 /*
2086 * Process the string.
2087 */
2088 while (cchStr > 0)
2089 {
2090 /* Look for dollar sign, marks variable expansion or dollar-escape. */
2091 int rc;
2092 const char *pchDollar = memchr(pchStr, '$', cchStr);
2093 if (pchDollar)
2094 {
2095 /*
2096 * Check for multiple dollar chars.
2097 */
2098 uint32_t offDollar = (uint32_t)(pchDollar - pchStr);
2099 uint32_t cDollars = 1;
2100 while ( offDollar + cDollars < cchStr
2101 && pchStr[offDollar + cDollars] == '$')
2102 cDollars++;
2103
2104 /*
2105 * Emit a string copy for any preceeding stuff, including half of
2106 * the dollars we found (dollar escape: $$ -> $).
2107 * (kmk_cc_exp_emit_copy_string ignore zero length strings).
2108 */
2109 kmk_cc_exp_emit_copy_string(ppBlockTail, pchStr, offDollar + cDollars / 2);
2110 pchStr += offDollar + cDollars;
2111 cchStr -= offDollar + cDollars;
2112
2113 /*
2114 * Odd number of dollar chars means there is a variable to expand
2115 * or function to call.
2116 */
2117 if (cDollars & 1)
2118 {
2119 if (cchStr > 0)
2120 {
2121 char const chOpen = *pchStr;
2122 if (chOpen == '(' || chOpen == '{')
2123 {
2124 /* There are several alternative ways of finding the ending
2125 parenthesis / braces.
2126
2127 GNU make does one thing for functions and variable containing
2128 any '$' chars before the first closing char. While for
2129 variables where a closing char comes before any '$' char, a
2130 simplified approach is taken. This means that for example:
2131
2132 Given VAR=var, the expressions "$(var())" and
2133 "$($(VAR)())" would be expanded differently.
2134 In the first case the variable "var(" would be
2135 used and in the second "var()".
2136
2137 This code will not duplicate this weird behavior, but work
2138 the same regardless of whether there is a '$' char before
2139 the first closing char. */
2140 make_function_ptr_t pfnFunction;
2141 const char *pszFunction;
2142 unsigned char cMaxArgs;
2143 unsigned char cMinArgs;
2144 char fExpandArgs;
2145 char const chClose = chOpen == '(' ? ')' : '}';
2146 char ch = 0;
2147 uint32_t cchName = 0;
2148 uint32_t cDepth = 1;
2149 uint32_t cMaxDepth = 1;
2150 cDollars = 0;
2151
2152 pchStr++;
2153 cchStr--;
2154
2155 /* First loop: Identify potential function calls and dynamic expansion. */
2156 KMK_CC_ASSERT(!func_char_map[(unsigned char)chOpen]);
2157 KMK_CC_ASSERT(!func_char_map[(unsigned char)chClose]);
2158 KMK_CC_ASSERT(!func_char_map[(unsigned char)'$']);
2159 while (cchName < cchStr)
2160 {
2161 ch = pchStr[cchName];
2162 if (!func_char_map[(unsigned char)ch])
2163 break;
2164 cchName++;
2165 }
2166
2167 if ( cchName >= MIN_FUNCTION_LENGTH
2168 && cchName <= MAX_FUNCTION_LENGTH
2169 && (ISBLANK(ch) || ch == chClose || cchName == cchStr)
2170 && (pfnFunction = lookup_function_for_compiler(pchStr, cchName, &cMinArgs, &cMaxArgs,
2171 &fExpandArgs, &pszFunction)) != NULL)
2172 {
2173 /*
2174 * It's a function invocation, we should count parameters while
2175 * looking for the end.
2176 * Note! We use cchName for the length of the argument list.
2177 */
2178 uint32_t cArgs = 1;
2179 if (ch != chClose)
2180 {
2181 /* Skip leading spaces before the first arg. */
2182 cchName++;
2183 while (cchName < cchStr && ISBLANK(pchStr[cchName]))
2184 cchName++;
2185
2186 pchStr += cchName;
2187 cchStr -= cchName;
2188 cchName = 0;
2189
2190 while (cchName < cchStr)
2191 {
2192 ch = pchStr[cchName];
2193 if (ch == ',')
2194 {
2195 if (cDepth == 1)
2196 cArgs++;
2197 }
2198 else if (ch == chClose)
2199 {
2200 if (!--cDepth)
2201 break;
2202 }
2203 else if (ch == chOpen)
2204 {
2205 if (++cDepth > cMaxDepth)
2206 cMaxDepth = cDepth;
2207 }
2208 else if (ch == '$')
2209 cDollars++;
2210 cchName++;
2211 }
2212 }
2213 else
2214 {
2215 pchStr += cchName;
2216 cchStr -= cchName;
2217 cchName = 0;
2218 }
2219 if (cArgs < cMinArgs)
2220 {
2221 fatal(NULL, _("Function '%s' takes a minimum of %d arguments: %d given"),
2222 pszFunction, (int)cMinArgs, (int)cArgs);
2223 return -1; /* not reached */
2224 }
2225 if (cDepth != 0)
2226 {
2227 fatal(NULL, chOpen == '('
2228 ? _("Missing closing parenthesis calling '%s'") : _("Missing closing braces calling '%s'"),
2229 pszFunction);
2230 return -1; /* not reached */
2231 }
2232 if (cMaxDepth > 16 && fExpandArgs)
2233 {
2234 fatal(NULL, _("Too many levels of nested function arguments expansions: %s"), pszFunction);
2235 return -1; /* not reached */
2236 }
2237 if (!fExpandArgs || cDollars == 0)
2238 kmk_cc_exp_emit_plain_function(ppBlockTail, pszFunction, pchStr, cchName,
2239 cArgs, chOpen, chClose, pfnFunction, cMaxArgs);
2240 else
2241 {
2242 rc = kmk_cc_exp_emit_dyn_function(ppBlockTail, pszFunction, pchStr, cchName,
2243 cArgs, chOpen, chClose, pfnFunction, cMaxArgs);
2244 if (rc != 0)
2245 return rc;
2246 }
2247 }
2248 else
2249 {
2250 /*
2251 * Variable, find the end while checking whether anything needs expanding.
2252 */
2253 if (ch == chClose)
2254 cDepth = 0;
2255 else if (cchName < cchStr)
2256 {
2257 if (ch != '$')
2258 {
2259 /* Second loop: Look for things that needs expanding. */
2260 while (cchName < cchStr)
2261 {
2262 ch = pchStr[cchName];
2263 if (ch == chClose)
2264 {
2265 if (!--cDepth)
2266 break;
2267 }
2268 else if (ch == chOpen)
2269 {
2270 if (++cDepth > cMaxDepth)
2271 cMaxDepth = cDepth;
2272 }
2273 else if (ch == '$')
2274 break;
2275 cchName++;
2276 }
2277 }
2278 if (ch == '$')
2279 {
2280 /* Third loop: Something needs expanding, just find the end. */
2281 cDollars = 1;
2282 cchName++;
2283 while (cchName < cchStr)
2284 {
2285 ch = pchStr[cchName];
2286 if (ch == chClose)
2287 {
2288 if (!--cDepth)
2289 break;
2290 }
2291 else if (ch == chOpen)
2292 {
2293 if (++cDepth > cMaxDepth)
2294 cMaxDepth = cDepth;
2295 }
2296 cchName++;
2297 }
2298 }
2299 }
2300 if (cDepth > 0) /* After warning, we just assume they're all there. */
2301 error(NULL, chOpen == '(' ? _("Missing closing parenthesis ") : _("Missing closing braces"));
2302 if (cMaxDepth >= 16)
2303 {
2304 fatal(NULL, _("Too many levels of nested variable expansions: '%.*s'"), (int)cchName + 2, pchStr - 1);
2305 return -1; /* not reached */
2306 }
2307 if (cDollars == 0)
2308 kmk_cc_exp_emit_plain_variable_maybe_sr(ppBlockTail, pchStr, cchName);
2309 else
2310 {
2311 rc = kmk_cc_exp_emit_dyn_variable(ppBlockTail, pchStr, cchName);
2312 if (rc != 0)
2313 return rc;
2314 }
2315 }
2316 pchStr += cchName + 1;
2317 cchStr -= cchName + (cDepth == 0);
2318 }
2319 else
2320 {
2321 /* Single character variable name. */
2322 kmk_cc_exp_emit_plain_variable_maybe_sr(ppBlockTail, pchStr, 1);
2323 pchStr++;
2324 cchStr--;
2325 }
2326 }
2327 else
2328 {
2329 error(NULL, _("Unexpected end of string after $"));
2330 break;
2331 }
2332 }
2333 }
2334 else
2335 {
2336 /*
2337 * Nothing more to expand, the remainder is a simple string copy.
2338 */
2339 kmk_cc_exp_emit_copy_string(ppBlockTail, pchStr, cchStr);
2340 break;
2341 }
2342 }
2343
2344 /*
2345 * Emit final instruction.
2346 */
2347 kmk_cc_exp_emit_return(ppBlockTail);
2348 return 0;
2349}
2350
2351
2352/**
2353 * Initializes string expansion program statistics.
2354 * @param pStats Pointer to the statistics structure to init.
2355 */
2356static void kmk_cc_exp_stats_init(PKMKCCEXPSTATS pStats)
2357{
2358 pStats->cchAvg = 0;
2359}
2360
2361
2362/**
2363 * Compiles a string expansion subprogram.
2364 *
2365 * The caller typically make a call to kmk_cc_block_get_next_ptr after this
2366 * function returns to figure out where to continue executing.
2367 *
2368 * @returns 0 on success, non-zero on failure.
2369 * @param ppBlockTail Pointer to the allocator tail pointer.
2370 * @param pchStr Pointer to the string to compile an expansion
2371 * program for (ASSUMED to be valid for the
2372 * lifetime of the program).
2373 * @param cchStr The length of the string to compile. Expected to
2374 * be at least on char long.
2375 * @param pSubprog The subprogram structure to initialize.
2376 */
2377static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubprog)
2378{
2379 KMK_CC_ASSERT(cchStr > 0);
2380 pSubprog->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
2381 kmk_cc_exp_stats_init(&pSubprog->Stats);
2382 return kmk_cc_exp_compile_common(ppBlockTail, pchStr, cchStr);
2383}
2384
2385
2386/**
2387 * Compiles a string expansion program.
2388 *
2389 * @returns Pointer to the program on success, NULL on failure.
2390 * @param pchStr Pointer to the string to compile an expansion
2391 * program for (ASSUMED to be valid for the
2392 * lifetime of the program).
2393 * @param cchStr The length of the string to compile. Expected to
2394 * be at least on char long.
2395 */
2396static PKMKCCEXPPROG kmk_cc_exp_compile(const char *pchStr, uint32_t cchStr)
2397{
2398 /*
2399 * Estimate block size, allocate one and initialize it.
2400 */
2401 PKMKCCEXPPROG pProg;
2402 PKMKCCBLOCK pBlock;
2403 pProg = kmk_cc_block_alloc_first(&pBlock, sizeof(*pProg),
2404 (kmk_cc_count_dollars(pchStr, cchStr) + 4) * 8);
2405 if (pProg)
2406 {
2407 pProg->pBlockTail = pBlock;
2408 pProg->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(pBlock);
2409 kmk_cc_exp_stats_init(&pProg->Stats);
2410 pProg->cRefs = 1;
2411#ifdef KMK_CC_STRICT
2412 pProg->uInputHash = kmk_cc_debug_string_hash_n(0, pchStr, cchStr);
2413#endif
2414
2415 /*
2416 * Join forces with the subprogram compilation code.
2417 */
2418 if (kmk_cc_exp_compile_common(&pProg->pBlockTail, pchStr, cchStr) == 0)
2419 {
2420#ifdef KMK_CC_WITH_STATS
2421 pBlock = pProg->pBlockTail;
2422 if (!pBlock->pNext)
2423 g_cSingleBlockExpProgs++;
2424 else if (!pBlock->pNext->pNext)
2425 g_cTwoBlockExpProgs++;
2426 else
2427 g_cMultiBlockExpProgs++;
2428 for (; pBlock; pBlock = pBlock->pNext)
2429 {
2430 g_cBlocksAllocatedExpProgs++;
2431 g_cbAllocatedExpProgs += pBlock->cbBlock;
2432 g_cbUnusedMemExpProgs += pBlock->cbBlock - pBlock->offNext;
2433 }
2434#endif
2435 return pProg;
2436 }
2437 kmk_cc_block_free_list(pProg->pBlockTail);
2438 }
2439 return NULL;
2440}
2441
2442
2443/**
2444 * Updates the recursive_without_dollar member of a variable structure.
2445 *
2446 * This avoid compiling string expansion programs with only a CopyString
2447 * instruction. By setting recursive_without_dollar to 1, code calling
2448 * kmk_cc_compile_variable_for_expand and kmk_exec_expand_to_var_buf will
2449 * instead treat start treating it as a simple variable, which is faster.
2450 *
2451 * @returns The updated recursive_without_dollar value.
2452 * @param pVar Pointer to the variable.
2453 */
2454static int kmk_cc_update_variable_recursive_without_dollar(struct variable *pVar)
2455{
2456 int fValue;
2457 KMK_CC_ASSERT(pVar->recursive_without_dollar == 0);
2458
2459 if (memchr(pVar->value, '$', pVar->value_length))
2460 fValue = -1;
2461 else
2462 fValue = 1;
2463 pVar->recursive_without_dollar = fValue;
2464
2465 return fValue;
2466}
2467
2468
2469/**
2470 * Compiles a variable for string expansion.
2471 *
2472 * @returns Pointer to the string expansion program on success, NULL if no
2473 * program was created.
2474 * @param pVar Pointer to the variable.
2475 */
2476struct kmk_cc_expandprog *kmk_cc_compile_variable_for_expand(struct variable *pVar)
2477{
2478 KMK_CC_ASSERT(strlen(pVar->value) == pVar->value_length);
2479 KMK_CC_ASSERT(!pVar->expandprog);
2480 KMK_CC_ASSERT(pVar->recursive_without_dollar <= 0);
2481
2482 if ( !pVar->expandprog
2483 && pVar->recursive)
2484 {
2485 if ( pVar->recursive_without_dollar < 0
2486 || ( pVar->recursive_without_dollar == 0
2487 && kmk_cc_update_variable_recursive_without_dollar(pVar) < 0) )
2488 {
2489 pVar->expandprog = kmk_cc_exp_compile(pVar->value, pVar->value_length);
2490 g_cVarForExpandCompilations++;
2491 }
2492 }
2493 return pVar->expandprog;
2494}
2495
2496
2497/**
2498 * String expansion execution worker for outputting a variable.
2499 *
2500 * @returns The new variable buffer position.
2501 * @param pVar The variable to reference.
2502 * @param pchDst The current variable buffer position.
2503 */
2504static char *kmk_exec_expand_worker_reference_variable(struct variable *pVar, char *pchDst)
2505{
2506 if (pVar->value_length > 0)
2507 {
2508 if (!pVar->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar))
2509 pchDst = variable_buffer_output(pchDst, pVar->value, pVar->value_length);
2510 else
2511 pchDst = reference_recursive_variable(pchDst, pVar);
2512 }
2513 else if (pVar->append)
2514 pchDst = reference_recursive_variable(pchDst, pVar);
2515 return pchDst;
2516}
2517
2518
2519/**
2520 * Executes a stream string expansion instructions, outputting to the current
2521 * varaible buffer.
2522 *
2523 * @returns The new variable buffer position.
2524 * @param pInstrCore The instruction to start executing at.
2525 * @param pchDst The current variable buffer position.
2526 */
2527static char *kmk_exec_expand_instruction_stream_to_var_buf(PKMKCCEXPCORE pInstrCore, char *pchDst)
2528{
2529 for (;;)
2530 {
2531 switch (pInstrCore->enmOpcode)
2532 {
2533 case kKmkCcExpInstr_CopyString:
2534 {
2535 PKMKCCEXPCOPYSTRING pInstr = (PKMKCCEXPCOPYSTRING)pInstrCore;
2536 pchDst = variable_buffer_output(pchDst, pInstr->pachSrc, pInstr->cchCopy);
2537
2538 pInstrCore = &(pInstr + 1)->Core;
2539 break;
2540 }
2541
2542 case kKmkCcExpInstr_PlainVariable:
2543 {
2544 PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)pInstrCore;
2545 struct variable *pVar = lookup_variable_strcached(pInstr->pszName);
2546 if (pVar)
2547 pchDst = kmk_exec_expand_worker_reference_variable(pVar, pchDst);
2548 else
2549 warn_undefined(pInstr->pszName, strcache2_get_len(&variable_strcache, pInstr->pszName));
2550
2551 pInstrCore = &(pInstr + 1)->Core;
2552 break;
2553 }
2554
2555 case kKmkCcExpInstr_DynamicVariable:
2556 {
2557 PKMKCCEXPDYNVAR pInstr = (PKMKCCEXPDYNVAR)pInstrCore;
2558 struct variable *pVar;
2559 uint32_t cchName;
2560 char *pszName = kmk_exec_expand_subprog_to_tmp(&pInstr->Subprog, &cchName);
2561 char *pszColon = (char *)memchr(pszName, ':', cchName);
2562 char *pszEqual;
2563 if ( pszColon == NULL
2564 || (pszEqual = (char *)memchr(pszColon + 1, '=', &pszName[cchName] - pszColon - 1)) == NULL
2565 || pszEqual == pszColon + 1)
2566 {
2567 pVar = lookup_variable(pszName, cchName);
2568 if (pVar)
2569 pchDst = kmk_exec_expand_worker_reference_variable(pVar, pchDst);
2570 else
2571 warn_undefined(pszName, cchName);
2572 }
2573 else if (pszColon != pszName)
2574 {
2575 /*
2576 * Oh, we have to do search and replace. How tedious.
2577 * Since the variable name is a temporary buffer, we can transform
2578 * the strings into proper search and replacement patterns directly.
2579 */
2580 pVar = lookup_variable(pszName, pszColon - pszName);
2581 if (pVar)
2582 {
2583 char const *pszExpandedVarValue = pVar->recursive ? recursively_expand(pVar) : pVar->value;
2584 char *pszSearchPat = pszColon + 1;
2585 char *pszReplacePat = pszEqual + 1;
2586 const char *pchPctSearchPat;
2587 const char *pchPctReplacePat;
2588
2589 *pszEqual = '\0';
2590 pchPctSearchPat = find_percent(pszSearchPat);
2591 pchPctReplacePat = find_percent(pszReplacePat);
2592
2593 if (!pchPctReplacePat)
2594 {
2595 if (pszReplacePat[-2] != '\0') /* On the offchance that a pct was unquoted by find_percent. */
2596 {
2597 memmove(pszName + 1, pszSearchPat, pszReplacePat - pszSearchPat);
2598 if (pchPctSearchPat)
2599 pchPctSearchPat -= pszSearchPat - &pszName[1];
2600 pszSearchPat = &pszName[1];
2601 }
2602 pchPctReplacePat = --pszReplacePat;
2603 *pszReplacePat = '%';
2604 }
2605
2606 if (!pchPctSearchPat)
2607 {
2608 pchPctSearchPat = --pszSearchPat;
2609 *pszSearchPat = '%';
2610 }
2611
2612 pchDst = patsubst_expand_pat(pchDst, pszExpandedVarValue,
2613 pszSearchPat, pszReplacePat,
2614 pchPctSearchPat, pchPctReplacePat);
2615
2616 if (pVar->recursive)
2617 free((void *)pszExpandedVarValue);
2618 }
2619 else
2620 warn_undefined(pszName, pszColon - pszName);
2621 }
2622 free(pszName);
2623
2624 pInstrCore = pInstr->pNext;
2625 break;
2626 }
2627
2628
2629 case kKmkCcExpInstr_SearchAndReplacePlainVariable:
2630 {
2631 PKMKCCEXPSRPLAINVAR pInstr = (PKMKCCEXPSRPLAINVAR)pInstrCore;
2632 struct variable *pVar = lookup_variable_strcached(pInstr->pszName);
2633 if (pVar)
2634 {
2635 char const *pszExpandedVarValue = pVar->recursive ? recursively_expand(pVar) : pVar->value;
2636 pchDst = patsubst_expand_pat(pchDst,
2637 pszExpandedVarValue,
2638 pInstr->pszSearchPattern,
2639 pInstr->pszReplacePattern,
2640 &pInstr->pszSearchPattern[pInstr->offPctSearchPattern],
2641 &pInstr->pszReplacePattern[pInstr->offPctReplacePattern]);
2642 if (pVar->recursive)
2643 free((void *)pszExpandedVarValue);
2644 }
2645 else
2646 warn_undefined(pInstr->pszName, strcache2_get_len(&variable_strcache, pInstr->pszName));
2647
2648 pInstrCore = pInstr->pNext;
2649 break;
2650 }
2651
2652 case kKmkCcExpInstr_PlainFunction:
2653 {
2654 PKMKCCEXPPLAINFUNC pInstr = (PKMKCCEXPPLAINFUNC)pInstrCore;
2655 uint32_t iArg;
2656 if (!pInstr->FnCore.fDirty)
2657 {
2658#ifdef KMK_CC_STRICT
2659 uint32_t uCrcBefore = 0;
2660 uint32_t uCrcAfter = 0;
2661 iArg = pInstr->FnCore.cArgs;
2662 while (iArg-- > 0)
2663 uCrcBefore = kmk_cc_debug_string_hash(uCrcBefore, pInstr->apszArgs[iArg]);
2664#endif
2665
2666 pchDst = pInstr->FnCore.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->FnCore.pszFuncName);
2667
2668#ifdef KMK_CC_STRICT
2669 iArg = pInstr->FnCore.cArgs;
2670 while (iArg-- > 0)
2671 uCrcAfter = kmk_cc_debug_string_hash(uCrcAfter, pInstr->apszArgs[iArg]);
2672 KMK_CC_ASSERT(uCrcBefore == uCrcAfter);
2673#endif
2674 }
2675 else
2676 {
2677 char **papszShadowArgs = xmalloc((pInstr->FnCore.cArgs * 2 + 1) * sizeof(papszShadowArgs[0]));
2678 char **papszArgs = &papszShadowArgs[pInstr->FnCore.cArgs];
2679
2680 iArg = pInstr->FnCore.cArgs;
2681 papszArgs[iArg] = NULL;
2682 while (iArg-- > 0)
2683 papszArgs[iArg] = papszShadowArgs[iArg] = xstrdup(pInstr->apszArgs[iArg]);
2684
2685 pchDst = pInstr->FnCore.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->FnCore.pszFuncName);
2686
2687 iArg = pInstr->FnCore.cArgs;
2688 while (iArg-- > 0)
2689 free(papszShadowArgs[iArg]);
2690 free(papszShadowArgs);
2691 }
2692
2693 pInstrCore = pInstr->FnCore.pNext;
2694 break;
2695 }
2696
2697 case kKmkCcExpInstr_DynamicFunction:
2698 {
2699 PKMKCCEXPDYNFUNC pInstr = (PKMKCCEXPDYNFUNC)pInstrCore;
2700 char **papszArgsShadow = xmalloc( (pInstr->FnCore.cArgs * 2 + 1) * sizeof(char *));
2701 char **papszArgs = &papszArgsShadow[pInstr->FnCore.cArgs];
2702 uint32_t iArg;
2703
2704 if (!pInstr->FnCore.fDirty)
2705 {
2706#ifdef KMK_CC_STRICT
2707 uint32_t uCrcBefore = 0;
2708 uint32_t uCrcAfter = 0;
2709#endif
2710 iArg = pInstr->FnCore.cArgs;
2711 papszArgs[iArg] = NULL;
2712 while (iArg-- > 0)
2713 {
2714 char *pszArg;
2715 if (pInstr->aArgs[iArg].fSubprog)
2716 pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.Subprog, NULL);
2717 else
2718 pszArg = (char *)pInstr->aArgs[iArg].u.Plain.psz;
2719 papszArgsShadow[iArg] = pszArg;
2720 papszArgs[iArg] = pszArg;
2721#ifdef KMK_CC_STRICT
2722 uCrcBefore = kmk_cc_debug_string_hash(uCrcBefore, pszArg);
2723#endif
2724 }
2725 pchDst = pInstr->FnCore.pfnFunction(pchDst, papszArgs, pInstr->FnCore.pszFuncName);
2726
2727 iArg = pInstr->FnCore.cArgs;
2728 while (iArg-- > 0)
2729 {
2730#ifdef KMK_CC_STRICT
2731 KMK_CC_ASSERT(papszArgsShadow[iArg] == papszArgs[iArg]);
2732 uCrcAfter = kmk_cc_debug_string_hash(uCrcAfter, papszArgsShadow[iArg]);
2733#endif
2734 if (pInstr->aArgs[iArg].fSubprog)
2735 free(papszArgsShadow[iArg]);
2736 }
2737 KMK_CC_ASSERT(uCrcBefore == uCrcAfter);
2738 }
2739 else
2740 {
2741 iArg = pInstr->FnCore.cArgs;
2742 papszArgs[iArg] = NULL;
2743 while (iArg-- > 0)
2744 {
2745 char *pszArg;
2746 if (pInstr->aArgs[iArg].fSubprog)
2747 pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.Subprog, NULL);
2748 else
2749 pszArg = xstrdup(pInstr->aArgs[iArg].u.Plain.psz);
2750 papszArgsShadow[iArg] = pszArg;
2751 papszArgs[iArg] = pszArg;
2752 }
2753
2754 pchDst = pInstr->FnCore.pfnFunction(pchDst, papszArgs, pInstr->FnCore.pszFuncName);
2755
2756 iArg = pInstr->FnCore.cArgs;
2757 while (iArg-- > 0)
2758 free(papszArgsShadow[iArg]);
2759 }
2760 free(papszArgsShadow);
2761
2762 pInstrCore = pInstr->FnCore.pNext;
2763 break;
2764 }
2765
2766 case kKmkCcExpInstr_Jump:
2767 {
2768 PKMKCCEXPJUMP pInstr = (PKMKCCEXPJUMP)pInstrCore;
2769 pInstrCore = pInstr->pNext;
2770 break;
2771 }
2772
2773 case kKmkCcExpInstr_Return:
2774 return pchDst;
2775
2776 default:
2777 fatal(NULL, _("Unknown string expansion opcode: %d (%#x)"),
2778 (int)pInstrCore->enmOpcode, (int)pInstrCore->enmOpcode);
2779 return NULL;
2780 }
2781 }
2782}
2783
2784
2785/**
2786 * Updates the string expansion statistics.
2787 *
2788 * @param pStats The statistics structure to update.
2789 * @param cchResult The result lenght.
2790 */
2791void kmk_cc_exp_stats_update(PKMKCCEXPSTATS pStats, uint32_t cchResult)
2792{
2793 /*
2794 * The average is simplified and not an exact average for every
2795 * expansion that has taken place.
2796 */
2797 pStats->cchAvg = (pStats->cchAvg * 7 + cchResult) / 8;
2798}
2799
2800
2801/**
2802 * Execute a string expansion subprogram, outputting to a new heap buffer.
2803 *
2804 * @returns Pointer to the output buffer (hand to free when done).
2805 * @param pSubprog The subprogram to execute.
2806 * @param pcchResult Where to return the size of the result. Optional.
2807 */
2808static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubprog, uint32_t *pcchResult)
2809{
2810 char *pchOldVarBuf;
2811 unsigned int cbOldVarBuf;
2812 char *pchDst;
2813 char *pszResult;
2814 uint32_t cchResult;
2815
2816 /*
2817 * Temporarily replace the variable buffer while executing the instruction
2818 * stream for this subprogram.
2819 */
2820 pchDst = install_variable_buffer_with_hint(&pchOldVarBuf, &cbOldVarBuf,
2821 pSubprog->Stats.cchAvg ? pSubprog->Stats.cchAvg + 32 : 256);
2822
2823 pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pSubprog->pFirstInstr, pchDst);
2824
2825 /* Ensure that it's terminated. */
2826 pchDst = variable_buffer_output(pchDst, "\0", 1) - 1;
2827
2828 /* Grab the result buffer before restoring the previous one. */
2829 pszResult = variable_buffer;
2830 cchResult = (uint32_t)(pchDst - pszResult);
2831 if (pcchResult)
2832 *pcchResult = cchResult;
2833 kmk_cc_exp_stats_update(&pSubprog->Stats, cchResult);
2834
2835 variable_buffer = pchOldVarBuf;
2836 variable_buffer_length = cbOldVarBuf;
2837
2838 return pszResult;
2839}
2840
2841
2842/**
2843 * Execute a string expansion program, outputting to the current variable
2844 * buffer.
2845 *
2846 * @returns New variable buffer position.
2847 * @param pProg The program to execute.
2848 * @param pchDst The current varaible buffer position.
2849 */
2850static char *kmk_exec_expand_prog_to_var_buf(PKMKCCEXPPROG pProg, char *pchDst)
2851{
2852 uint32_t cchResult;
2853 uint32_t offStart = (uint32_t)(pchDst - variable_buffer);
2854
2855 if (pProg->Stats.cchAvg >= variable_buffer_length - offStart)
2856 pchDst = ensure_variable_buffer_space(pchDst, offStart + pProg->Stats.cchAvg + 32);
2857
2858 KMK_CC_ASSERT(pProg->cRefs > 0);
2859 pProg->cRefs++;
2860
2861 pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pProg->pFirstInstr, pchDst);
2862
2863 pProg->cRefs--;
2864 KMK_CC_ASSERT(pProg->cRefs > 0);
2865
2866 cchResult = (uint32_t)(pchDst - variable_buffer);
2867 KMK_CC_ASSERT(cchResult >= offStart);
2868 cchResult -= offStart;
2869 kmk_cc_exp_stats_update(&pProg->Stats, cchResult);
2870 g_cVarForExpandExecs++;
2871
2872 return pchDst;
2873}
2874
2875
2876/**
2877 * Expands a variable into a variable buffer using its expandprog.
2878 *
2879 * @returns The new variable buffer position.
2880 * @param pVar Pointer to the variable. Must have a program.
2881 * @param pchDst Pointer to the current variable buffer position.
2882 */
2883char *kmk_exec_expand_to_var_buf(struct variable *pVar, char *pchDst)
2884{
2885 KMK_CC_ASSERT(pVar->expandprog);
2886 KMK_CC_ASSERT(pVar->expandprog->uInputHash == kmk_cc_debug_string_hash(0, pVar->value));
2887 return kmk_exec_expand_prog_to_var_buf(pVar->expandprog, pchDst);
2888}
2889
2890
2891
2892
2893
2894/*
2895 *
2896 * Makefile evaluation programs.
2897 * Makefile evaluation programs.
2898 * Makefile evaluation programs.
2899 *
2900 */
2901
2902static size_t kmk_cc_eval_detect_eol_style(char *pchFirst, char *pchSecond, const char *pszContent, size_t cchContent)
2903{
2904 /* Look for LF first. */
2905 const char *pszTmp = (const char *)memchr(pszContent, '\n', cchContent);
2906 if (pszTmp)
2907 {
2908 /* CRLF? */
2909 if (pszTmp != pszContent && pszTmp[-1] == '\r')
2910 {
2911 *pchFirst = '\r';
2912 *pchSecond = '\n';
2913 return 2;
2914 }
2915
2916 /* No, LF or LFCR. (pszContent is zero terminated, so no bounds checking necessary.) */
2917 *pchFirst = '\n';
2918 if (pszTmp[1] != '\r')
2919 {
2920 *pchSecond = 0;
2921 return 1;
2922 }
2923 *pchSecond = '\r';
2924 return 2;
2925 }
2926
2927 /* Probably no EOLs here. */
2928 if (memchr(pszContent, '\r', cchContent) == NULL)
2929 {
2930 *pchSecond = *pchFirst = 0;
2931 return 0;
2932 }
2933
2934 /* kind of unlikely */
2935 *pchFirst = '\r';
2936 *pchSecond = 0;
2937 return 1;
2938}
2939
2940
2941#if 0
2942/**
2943 * Checks whether we've got an EOL escape sequence or not.
2944 *
2945 * @returns non-zero if escaped EOL, 0 if not (i.e. actual EOL).
2946 * @param pszContent The string pointer @a offEol is relative to.
2947 * @param offEol The offset of the first EOL char.
2948 */
2949static unsigned kmk_cc_eval_is_eol_escape_seq(const char *pszContent, size_t offEol)
2950{
2951 /* The caller has already checked out two backslashes. */
2952 size_t offFirstBackslash = offEol;
2953 KMK_CC_ASSERT(offFirstBackslash >= 2);
2954 offFirstBackslash -= 2;
2955
2956 /* Find the first backslash. */
2957 while (offFirstBackslash > 0 && pszContent[offFirstBackslash - 1] == '\\')
2958 offFirstBackslash--;
2959
2960 /* Odd number -> escaped EOL; Even number -> real EOL; */
2961 return (offEol - offFirstBackslash) & 1;
2962}
2963#endif
2964
2965
2966
2967/**
2968 * Tokens (for KMKCCEVALWORD).
2969 */
2970typedef enum kmk_cc_eval_token
2971{
2972 /** Invalid token value 0. */
2973 kKmkCcEvalToken_Invalid = 0,
2974
2975 /** Plain word. */
2976 kKmkCcEvalToken_WordPlain,
2977 /** Word that maybe in need of expanding. */
2978 kKmkCcEvalToken_WordWithDollar,
2979
2980 /** Recipe colon. */
2981 kKmkCcEvalToken_colon,
2982 /** Recipe double colon. */
2983 kKmkCcEvalToken_double_colon,
2984 /** Recipe multi target plus. */
2985 kKmkCcEvalToken_plus,
2986 /** Recipe multi target plus-maybe (+|). */
2987 kKmkCcEvalToken_plus_maybe,
2988 /** Recipe semicolon. */
2989 kKmkCcEvalToken_semicolon,
2990
2991 /** End of valid token values (not included). */
2992 kKmkCcEvalToken_End
2993} KMKCCEVALTOKEN;
2994
2995/**
2996 * A tokenized word.
2997 */
2998typedef struct kmk_cc_eval_word
2999{
3000 /** The token word (lexeme). */
3001 const char *pchWord;
3002 /** The length of the word (lexeme). */
3003 uint32_t cchWord;
3004 /** The token classification. */
3005 KMKCCEVALTOKEN enmToken;
3006} KMKCCEVALWORD;
3007typedef KMKCCEVALWORD *PKMKCCEVALWORD;
3008typedef KMKCCEVALWORD const *PCKMKCCEVALWORD;
3009
3010
3011/**
3012 * Escaped end-of-line sequence in the current line.
3013 */
3014typedef struct KMKCCEVALESCEOL
3015{
3016 /** Offset at which the EOL escape sequence starts for a non-command line. */
3017 size_t offEsc;
3018 /** Offset of the newline sequence. */
3019 size_t offEol;
3020} KMKCCEVALESCEOL;
3021typedef KMKCCEVALESCEOL *PKMKCCEVALESCEOL;
3022
3023
3024/**
3025 * String copy segment.
3026 */
3027typedef struct KMKCCEVALSTRCPYSEG
3028{
3029 /** The start. */
3030 const char *pchSrc;
3031 /** The number of chars to copy and whether to prepend space.
3032 * Negative values indicates that we should prepend a space. */
3033 ssize_t cchSrcAndPrependSpace;
3034} KMKCCEVALSTRCPYSEG;
3035typedef KMKCCEVALSTRCPYSEG *PKMKCCEVALSTRCPYSEG;
3036typedef KMKCCEVALSTRCPYSEG const *PCKMKCCEVALSTRCPYSEG;
3037
3038
3039typedef struct KMKCCEVALCOMPILER
3040{
3041 /** Pointer to the KMKCCEVALPROG::pBlockTail member. */
3042 PKMKCCBLOCK *ppBlockTail;
3043
3044 /** @name Line parsing state.
3045 * @{ */
3046 /** Offset of newline escape sequences in the current line.
3047 * This is only applicable if cEscEols is not zero. */
3048 PKMKCCEVALESCEOL paEscEols;
3049 /** The number of number of paEscEols entries we've allocated. */
3050 unsigned cEscEolsAllocated;
3051 /** Number of escaped EOLs (line count - 1). */
3052 unsigned cEscEols;
3053 /** The paEscEols entry corresponding to the current parsing location.
3054 * Still to be seen how accurate this can be made to be. */
3055 unsigned iEscEol;
3056
3057 /** The current line number for error handling / debugging (1-based). */
3058 unsigned iLine;
3059 /** The start offset (into pchContent) of the current line. */
3060 size_t offLine;
3061 /** Length of the current line, sans the final EOL and comments. */
3062 size_t cchLine;
3063 /** Length of the current line, sans the final EOL but with comments. */
3064 size_t cchLineWithComments;
3065
3066 /** The first char in an EOL sequence.
3067 * We ASSUMES that this char won't appear in any other sequence in the file,
3068 * thus skipping matching any subsequent chars. */
3069 char chFirstEol;
3070 /** The second char in an EOL sequence, if applicable. */
3071 char chSecondEol;
3072
3073 /** The length of the EOL sequence. */
3074 size_t cchEolSeq;
3075 /** The minimum length of an esacped EOL sequence (cchEolSeq + 1). */
3076 size_t cchEscEolSeq;
3077
3078 /** String copy segments. */
3079 PKMKCCEVALSTRCPYSEG paStrCopySegs;
3080 /** The number of segments that has been prepared. */
3081 unsigned cStrCopySegs;
3082 /** The number of segments we've allocated. */
3083 unsigned cStrCopySegsAllocated;
3084 /** @} */
3085
3086
3087 /** @name Recipe state.
3088 * @{ */
3089 /** Set if we're working on a recipe. */
3090 PKMKCCEVALRECIPE pRecipe;
3091 /** Set for ignoring recipes without targets (SunOS 4 Make). */
3092 uint8_t fNoTargetRecipe;
3093 /** The command prefix character. */
3094 char chCmdPrefix;
3095 /** @} */
3096
3097 /** @name Tokenzied words.
3098 * @{ */
3099 uint32_t cWords;
3100 uint32_t cWordsAllocated;
3101 PKMKCCEVALWORD paWords;
3102 /** @} */
3103
3104 /** @name Conditionals.
3105 * @{ */
3106 /** Current conditional stack depth. */
3107 unsigned cIfs;
3108 /** The conditional directive stack. */
3109 PKMKCCEVALIFCORE apIfs[KMK_CC_EVAL_MAX_IF_DEPTH];
3110 /** @} */
3111
3112 /** The program being compiled. */
3113 PKMKCCEVALPROG pEvalProg;
3114 /** Pointer to the content. */
3115 const char *pszContent;
3116 /** The amount of input to parse. */
3117 size_t cchContent;
3118} KMKCCEVALCOMPILER;
3119typedef KMKCCEVALCOMPILER *PKMKCCEVALCOMPILER;
3120
3121
3122static void kmk_cc_eval_init_compiler(PKMKCCEVALCOMPILER pCompiler, PKMKCCEVALPROG pEvalProg, unsigned iLine,
3123 const char *pszContent, size_t cchContent)
3124{
3125 pCompiler->ppBlockTail = &pEvalProg->pBlockTail;
3126
3127 pCompiler->pRecipe = NULL;
3128 pCompiler->fNoTargetRecipe = 0;
3129 pCompiler->chCmdPrefix = cmd_prefix;
3130
3131 pCompiler->cWordsAllocated = 0;
3132 pCompiler->paWords = NULL;
3133
3134 pCompiler->cEscEolsAllocated = 0;
3135 pCompiler->paEscEols = NULL;
3136 pCompiler->iLine = iLine;
3137
3138 pCompiler->cStrCopySegsAllocated = 0;
3139 pCompiler->paStrCopySegs = NULL;
3140
3141 pCompiler->cIfs = 0;
3142
3143 pCompiler->pEvalProg = pEvalProg;
3144 pCompiler->pszContent = pszContent;
3145 pCompiler->cchContent = cchContent;
3146
3147 /* Detect EOL style. */
3148 pCompiler->cchEolSeq = kmk_cc_eval_detect_eol_style(&pCompiler->chFirstEol, &pCompiler->chSecondEol,
3149 pszContent, cchContent);
3150 pCompiler->cchEscEolSeq = 1 + pCompiler->cchEolSeq;
3151}
3152
3153
3154static void kmk_cc_eval_delete_compiler(PKMKCCEVALCOMPILER pCompiler)
3155{
3156 if (pCompiler->paWords)
3157 free(pCompiler->paWords);
3158 if (pCompiler->paEscEols)
3159 free(pCompiler->paEscEols);
3160}
3161
3162
3163/**
3164 * Translates a makefile source pointer to a line number and offset.
3165 *
3166 * @returns Line number (1-based)
3167 * @param pCompiler The compiler state.
3168 * @param pszWhere There location to translate.
3169 * @param piColumn Where to return the line offset (1-based).
3170 */
3171static unsigned kmk_cc_eval_translate_location(PKMKCCEVALCOMPILER pCompiler, const char *pchWhere, unsigned *piColumn)
3172{
3173 unsigned iLine = pCompiler->iLine;
3174 size_t offLine = pCompiler->offLine;
3175 size_t off = pchWhere - pCompiler->pszContent;
3176 unsigned i = 0;
3177 while ( i < pCompiler->cEscEols
3178 && off > pCompiler->paEscEols[i].offEol)
3179 {
3180 offLine = pCompiler->paEscEols[i].offEol + 1 + pCompiler->cchEolSeq;
3181 iLine++;
3182 i++;
3183 }
3184 KMK_CC_ASSERT(off <= pCompiler->cchContent);
3185 if (piColumn)
3186 *piColumn = (unsigned)(off - offLine) + 1;
3187 return iLine;
3188}
3189
3190
3191static void KMK_CC_FN_NO_RETURN kmk_cc_eval_fatal(PKMKCCEVALCOMPILER pCompiler, const char *pchWhere, const char *pszMsg, ...)
3192{
3193 va_list va;
3194 log_working_directory(1);
3195
3196 /*
3197 * If we have a pointer location, use it to figure out the exact line and column.
3198 */
3199 if (pchWhere)
3200 {
3201 unsigned iColumn;
3202 unsigned iLine = kmk_cc_eval_translate_location(pCompiler, pchWhere, &iColumn);
3203
3204 if (pCompiler->pEvalProg->pszVarName)
3205 fprintf(stderr, "%s:%u:%u: *** fatal parsing error in %s: ",
3206 pCompiler->pEvalProg->pszFilename, iLine, iColumn, pCompiler->pEvalProg->pszVarName);
3207 else
3208 fprintf(stderr, "%s:%u:%u: *** fatal parsing error: ",
3209 pCompiler->pEvalProg->pszFilename, iLine, iColumn);
3210 }
3211 else if (pCompiler->pEvalProg->pszVarName)
3212 fprintf(stderr, "%s:%u: *** fatal parsing error in %s: ",
3213 pCompiler->pEvalProg->pszFilename, pCompiler->iLine, pCompiler->pEvalProg->pszVarName);
3214 else
3215 fprintf(stderr, "%s:%u: *** fatal parsing error: ",
3216 pCompiler->pEvalProg->pszFilename, pCompiler->iLine);
3217
3218 /*
3219 * Print the message and die.
3220 */
3221 va_start(va, pszMsg);
3222 vfprintf(stderr, pszMsg, va);
3223 va_end(va);
3224 fputs(". Stop.\n", stderr);
3225
3226 for (;;)
3227 die(2);
3228}
3229
3230
3231static KMK_CC_FN_NO_RETURN void
3232kmk_cc_eval_fatal_eol(PKMKCCEVALCOMPILER pCompiler, const char *pchEol, unsigned iLine, size_t offLine)
3233{
3234 pCompiler->iLine = iLine;
3235 pCompiler->offLine = offLine;
3236
3237 for (;;)
3238 kmk_cc_eval_fatal(pCompiler, pchEol, "Missing 2nd EOL character: found %#x instead of %#x\n",
3239 pchEol, pCompiler->chSecondEol);
3240}
3241
3242
3243static void kmk_cc_eval_warn(PKMKCCEVALCOMPILER pCompiler, const char *pchWhere, const char *pszMsg, ...)
3244{
3245 va_list va;
3246
3247 log_working_directory(1);
3248
3249 /*
3250 * If we have a pointer location, use it to figure out the exact line and column.
3251 */
3252 if (pchWhere)
3253 {
3254 unsigned iColumn;
3255 unsigned iLine = kmk_cc_eval_translate_location(pCompiler, pchWhere, &iColumn);
3256
3257 if (pCompiler->pEvalProg->pszVarName)
3258 fprintf(stderr, "%s:%u:%u: *** warning in %s: ",
3259 pCompiler->pEvalProg->pszFilename, iLine, iColumn, pCompiler->pEvalProg->pszVarName);
3260 else
3261 fprintf(stderr, "%s:%u:%u: *** warning: ",
3262 pCompiler->pEvalProg->pszFilename, iLine, iColumn);
3263 }
3264 else if (pCompiler->pEvalProg->pszVarName)
3265 fprintf(stderr, "%s:%u: *** warning in %s: ",
3266 pCompiler->pEvalProg->pszFilename, pCompiler->iLine, pCompiler->pEvalProg->pszVarName);
3267 else
3268 fprintf(stderr, "%s:%u: *** warning: ",
3269 pCompiler->pEvalProg->pszFilename, pCompiler->iLine);
3270
3271 /*
3272 * Print the message.
3273 */
3274 va_start(va, pszMsg);
3275 vfprintf(stderr, pszMsg, va);
3276 va_end(va);
3277 fputs(".\n", stderr);
3278}
3279
3280
3281/**
3282 * Compiles a string expansion subprogram.
3283 *
3284 * @param pCompiler The compiler state.
3285 * @param pszExpr The expression to compile.
3286 * @param cchExpr The length of the expression.
3287 * @param pSubprog The subprogram to compile.
3288 */
3289static void kmk_cc_eval_compile_string_exp_subprog(PKMKCCEVALCOMPILER pCompiler, const char *pszExpr, size_t cchExpr,
3290 PKMKCCEXPSUBPROG pSubprog)
3291{
3292 int rc = kmk_cc_exp_compile_subprog(pCompiler->ppBlockTail, pszExpr, cchExpr, pSubprog);
3293 if (rc == 0)
3294 return;
3295 kmk_cc_eval_fatal(pCompiler, NULL, "String expansion compile error");
3296}
3297
3298
3299/**
3300 * Initializes a subprogam or plain operand structure.
3301 *
3302 * @param pCompiler The compiler state.
3303 * @param pOperand The subprogram or plain structure to init.
3304 * @param pszString The string.
3305 * @param cchString The length of the string.
3306 * @param fPlain Whether it's plain or not. If not, we'll compile it.
3307 */
3308static void kmk_cc_eval_init_subprogram_or_plain(PKMKCCEVALCOMPILER pCompiler, PKMKCCEXPSUBPROGORPLAIN pOperand,
3309 const char *pszString, size_t cchString, int fPlain)
3310{
3311 pOperand->fPlainIsInVarStrCache = 0;
3312 pOperand->bUser = 0;
3313 pOperand->bUser2 = 0;
3314 pOperand->fSubprog = fPlain;
3315 if (fPlain)
3316 {
3317 pOperand->u.Plain.cch = cchString;
3318 pOperand->u.Plain.psz = pszString;
3319 }
3320 else
3321 kmk_cc_eval_compile_string_exp_subprog(pCompiler, pszString, cchString, &pOperand->u.Subprog);
3322}
3323
3324/**
3325 * Initializes an array of subprogram-or-plain (spp) operands from a word array.
3326 *
3327 * The words will be duplicated and the caller must therefore call
3328 * kmk_cc_block_realign() when done (it's not done here as the caller may
3329 * initialize several string operands and we don't want any unnecessary
3330 * fragmentation).
3331 *
3332 * @param pCompiler The compiler state.
3333 * @param cWords The number of words to copy.
3334 * @param paSrc The source words.
3335 * @param paDst The destination subprogram-or-plain array.
3336 */
3337static void kmk_cc_eval_init_spp_array_from_duplicated_words(PKMKCCEVALCOMPILER pCompiler, unsigned cWords,
3338 PKMKCCEVALWORD paSrc, PKMKCCEXPSUBPROGORPLAIN paDst)
3339{
3340 unsigned i;
3341 for (i = 0; i < cWords; i++)
3342 {
3343 const char *pszCopy = kmk_cc_block_strdup(pCompiler->ppBlockTail, paSrc[i].pchWord, paSrc[i].cchWord);
3344 paDst[i].fPlainIsInVarStrCache = 0;
3345 paDst[i].bUser = 0;
3346 paDst[i].bUser2 = 0;
3347 if (paSrc[i].enmToken == kKmkCcEvalToken_WordWithDollar)
3348 {
3349 paDst[i].fSubprog = 1;
3350 kmk_cc_block_realign(pCompiler->ppBlockTail);
3351 kmk_cc_eval_compile_string_exp_subprog(pCompiler, pszCopy, paSrc[i].cchWord, &paDst[i].u.Subprog);
3352 }
3353 else
3354 {
3355 paDst[i].fSubprog = 0;
3356 paDst[i].u.Plain.cch = paSrc[i].cchWord;
3357 paDst[i].u.Plain.psz = pszCopy;
3358 }
3359 KMK_CC_EVAL_DPRINTF((" %s\n", pszCopy));
3360 }
3361}
3362
3363
3364
3365/** @name KMK_CC_WORD_COMP_CONST_XXX - Optimal(/insane) constant work matching.
3366 * @{
3367 */
3368#if (defined(KBUILD_ARCH_X86) || defined(KBUILD_ARCH_AMD64)) /* Unaligned access is reasonably cheap. */ \
3369 && !defined(GCC_ADDRESS_SANITIZER)
3370# define KMK_CC_WORD_COMP_CONST_2(a_pchLine, a_pszWord) \
3371 ( *(uint16_t const *)(a_pchLine) == *(uint16_t const *)(a_pszWord) )
3372# define KMK_CC_WORD_COMP_CONST_3(a_pchLine, a_pszWord) \
3373 ( *(uint16_t const *)(a_pchLine) == *(uint16_t const *)(a_pszWord) \
3374 && (a_pchLine)[2] == (a_pszWord)[2] )
3375# define KMK_CC_WORD_COMP_CONST_4(a_pchLine, a_pszWord) \
3376 ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) )
3377# define KMK_CC_WORD_COMP_CONST_5(a_pchLine, a_pszWord) \
3378 ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) \
3379 && (a_pchLine)[4] == (a_pszWord)[4] )
3380# define KMK_CC_WORD_COMP_CONST_6(a_pchLine, a_pszWord) \
3381 ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) \
3382 && ((uint16_t const *)(a_pchLine))[2] == ((uint16_t const *)(a_pszWord))[2] )
3383# define KMK_CC_WORD_COMP_CONST_7(a_pchLine, a_pszWord) \
3384 ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) \
3385 && ((uint16_t const *)(a_pchLine))[2] == ((uint16_t const *)(a_pszWord))[2] \
3386 && (a_pchLine)[6] == (a_pszWord)[6] )
3387# define KMK_CC_WORD_COMP_CONST_8(a_pchLine, a_pszWord) \
3388 ( *(uint64_t const *)(a_pchLine) == *(uint64_t const *)(a_pszWord) )
3389# define KMK_CC_WORD_COMP_CONST_10(a_pchLine, a_pszWord) \
3390 ( *(uint64_t const *)(a_pchLine) == *(uint64_t const *)(a_pszWord) \
3391 && ((uint16_t const *)(a_pchLine))[4] == ((uint16_t const *)(a_pszWord))[4] )
3392# define KMK_CC_WORD_COMP_CONST_16(a_pchLine, a_pszWord) \
3393 ( *(uint64_t const *)(a_pchLine) == *(uint64_t const *)(a_pszWord) \
3394 && ((uint64_t const *)(a_pchLine))[1] == ((uint64_t const *)(a_pszWord))[1] )
3395#else
3396# define KMK_CC_WORD_COMP_CONST_2(a_pchLine, a_pszWord) \
3397 ( (a_pchLine)[0] == (a_pszWord)[0] \
3398 && (a_pchLine)[1] == (a_pszWord)[1] )
3399# define KMK_CC_WORD_COMP_CONST_3(a_pchLine, a_pszWord) \
3400 ( (a_pchLine)[0] == (a_pszWord)[0] \
3401 && (a_pchLine)[1] == (a_pszWord)[1] \
3402 && (a_pchLine)[2] == (a_pszWord)[2] )
3403# define KMK_CC_WORD_COMP_CONST_4(a_pchLine, a_pszWord) \
3404 ( (a_pchLine)[0] == (a_pszWord)[0] \
3405 && (a_pchLine)[1] == (a_pszWord)[1] \
3406 && (a_pchLine)[2] == (a_pszWord)[2] \
3407 && (a_pchLine)[3] == (a_pszWord)[3] )
3408# define KMK_CC_WORD_COMP_CONST_5(a_pchLine, a_pszWord) \
3409 ( (a_pchLine)[0] == (a_pszWord)[0] \
3410 && (a_pchLine)[1] == (a_pszWord)[1] \
3411 && (a_pchLine)[2] == (a_pszWord)[2] \
3412 && (a_pchLine)[3] == (a_pszWord)[3] \
3413 && (a_pchLine)[4] == (a_pszWord)[4] )
3414# define KMK_CC_WORD_COMP_CONST_6(a_pchLine, a_pszWord) \
3415 ( (a_pchLine)[0] == (a_pszWord)[0] \
3416 && (a_pchLine)[1] == (a_pszWord)[1] \
3417 && (a_pchLine)[2] == (a_pszWord)[2] \
3418 && (a_pchLine)[3] == (a_pszWord)[3] \
3419 && (a_pchLine)[4] == (a_pszWord)[4] \
3420 && (a_pchLine)[5] == (a_pszWord)[5] )
3421# define KMK_CC_WORD_COMP_CONST_7(a_pchLine, a_pszWord) \
3422 ( (a_pchLine)[0] == (a_pszWord)[0] \
3423 && (a_pchLine)[1] == (a_pszWord)[1] \
3424 && (a_pchLine)[2] == (a_pszWord)[2] \
3425 && (a_pchLine)[3] == (a_pszWord)[3] \
3426 && (a_pchLine)[4] == (a_pszWord)[4] \
3427 && (a_pchLine)[5] == (a_pszWord)[5] \
3428 && (a_pchLine)[6] == (a_pszWord)[6] )
3429# define KMK_CC_WORD_COMP_CONST_8(a_pchLine, a_pszWord) \
3430 ( (a_pchLine)[0] == (a_pszWord)[0] \
3431 && (a_pchLine)[1] == (a_pszWord)[1] \
3432 && (a_pchLine)[2] == (a_pszWord)[2] \
3433 && (a_pchLine)[3] == (a_pszWord)[3] \
3434 && (a_pchLine)[4] == (a_pszWord)[4] \
3435 && (a_pchLine)[5] == (a_pszWord)[5] \
3436 && (a_pchLine)[6] == (a_pszWord)[6] \
3437 && (a_pchLine)[7] == (a_pszWord)[7] )
3438# define KMK_CC_WORD_COMP_CONST_10(a_pchLine, a_pszWord) \
3439 ( (a_pchLine)[0] == (a_pszWord)[0] \
3440 && (a_pchLine)[1] == (a_pszWord)[1] \
3441 && (a_pchLine)[2] == (a_pszWord)[2] \
3442 && (a_pchLine)[3] == (a_pszWord)[3] \
3443 && (a_pchLine)[4] == (a_pszWord)[4] \
3444 && (a_pchLine)[5] == (a_pszWord)[5] \
3445 && (a_pchLine)[6] == (a_pszWord)[6] \
3446 && (a_pchLine)[7] == (a_pszWord)[7] \
3447 && (a_pchLine)[8] == (a_pszWord)[8] \
3448 && (a_pchLine)[9] == (a_pszWord)[9] )
3449# define KMK_CC_WORD_COMP_CONST_16(a_pchLine, a_pszWord) \
3450 ( (a_pchLine)[0] == (a_pszWord)[0] \
3451 && (a_pchLine)[1] == (a_pszWord)[1] \
3452 && (a_pchLine)[2] == (a_pszWord)[2] \
3453 && (a_pchLine)[3] == (a_pszWord)[3] \
3454 && (a_pchLine)[4] == (a_pszWord)[4] \
3455 && (a_pchLine)[5] == (a_pszWord)[5] \
3456 && (a_pchLine)[6] == (a_pszWord)[6] \
3457 && (a_pchLine)[7] == (a_pszWord)[7] \
3458 && (a_pchLine)[8] == (a_pszWord)[8] \
3459 && (a_pchLine)[9] == (a_pszWord)[9] \
3460 && (a_pchLine)[10] == (a_pszWord)[10] \
3461 && (a_pchLine)[11] == (a_pszWord)[11] \
3462 && (a_pchLine)[12] == (a_pszWord)[12] \
3463 && (a_pchLine)[13] == (a_pszWord)[13] \
3464 && (a_pchLine)[14] == (a_pszWord)[14] \
3465 && (a_pchLine)[15] == (a_pszWord)[15])
3466#endif
3467
3468/** See if the given string match a constant string. */
3469#define KMK_CC_STRCMP_CONST(a_pchLeft, a_cchLeft, a_pszConst, a_cchConst) \
3470 ( (a_cchLeft) == (a_cchConst) \
3471 && KMK_CC_WORD_COMP_CONST_##a_cchConst(a_pchLeft, a_pszConst) )
3472
3473/** See if a starting of a given length starts with a constant word. */
3474#define KMK_CC_EVAL_WORD_COMP_IS_EOL(a_pCompiler, a_pchLine, a_cchLine) \
3475 ( (a_cchLine) == 0 \
3476 || KMK_CC_EVAL_IS_SPACE((a_pchLine)[0]) \
3477 || ((a_pchLine)[0] == '\\' && (a_pchLine)[1] == (a_pCompiler)->chFirstEol) ) \
3478
3479/** See if a starting of a given length starts with a constant word. */
3480#define KMK_CC_EVAL_WORD_COMP_CONST(a_pCompiler, a_pchLine, a_cchLine, a_pszWord, a_cchWord) \
3481 ( (a_cchLine) >= (a_cchWord) \
3482 && ( (a_cchLine) == (a_cchWord) \
3483 || KMK_CC_EVAL_IS_SPACE((a_pchLine)[a_cchWord]) \
3484 || ((a_pchLine)[a_cchWord] == '\\' && (a_pchLine)[(a_cchWord) + 1] == (a_pCompiler)->chFirstEol) ) \
3485 && KMK_CC_WORD_COMP_CONST_##a_cchWord(a_pchLine, a_pszWord) )
3486/** @} */
3487
3488
3489/**
3490 * Checks if a_ch is a space after a word.
3491 *
3492 * Since there is always a terminating zero, the user can safely access a char
3493 * beyond @a a_cchLeft. However, that byte isn't necessarily a zero terminator
3494 * character, so we have to check @a a_cchLeft whether we're at the end of the
3495 * parsing input string.
3496 *
3497 * @returns true / false.
3498 * @param a_pCompiler The compiler instance data.
3499 * @param a_ch The character to inspect.
3500 * @param a_ch2 The character following it, in case of escaped EOL.
3501 * @param a_cchLeft The number of chars left to parse (from @a a_ch).
3502 */
3503#define KMK_CC_EVAL_IS_SPACE_AFTER_WORD(a_pCompiler, a_ch, a_ch2, a_cchLeft) \
3504 ( a_cchLeft == 0 \
3505 || KMK_CC_EVAL_IS_SPACE(a_ch) \
3506 || ((a_ch) == '\\' && (a_ch2) == (a_pCompiler)->chFirstEol) )
3507
3508
3509/**
3510 * Common path for space skipping worker functions when escaped EOLs may be
3511 * involed.
3512 *
3513 * @returns Points to the first non-space character or end of input.
3514 * @param pchWord The current position. There is some kind of char
3515 * @param cchLeft The current number of chars left to parse in the
3516 * current line.
3517 * @param pcchLeft Where to store the updated @a cchLeft value.
3518 * @param pCompiler The compiler instance data.
3519 */
3520static const char *kmk_cc_eval_skip_spaces_with_esc_eol(const char *pchWord, size_t cchLeft, size_t *pcchLeft,
3521 PKMKCCEVALCOMPILER pCompiler)
3522{
3523 /*
3524 * Skip further spaces. We unrolls 4 loops here.
3525 * ASSUMES cchEscEolSeq is either 2 or 3!
3526 */
3527 KMK_CC_ASSERT(pCompiler->cchEscEolSeq == 2 || pCompiler->cchEscEolSeq == 3);
3528 KMK_CC_ASSERT(pCompiler->iEscEol < pCompiler->cEscEols);
3529 while (cchLeft >= 4)
3530 {
3531 /* First char. */
3532 char ch = pchWord[0];
3533 if (KMK_CC_EVAL_IS_SPACE(ch))
3534 { /* maybe likely */ }
3535 else if ( ch == '\\'
3536 && pchWord[1] == pCompiler->chFirstEol)
3537 {
3538 pchWord += pCompiler->cchEscEolSeq;
3539 cchLeft -= pCompiler->cchEscEolSeq;
3540 pCompiler->iEscEol++;
3541 continue;
3542 }
3543 else
3544 {
3545 *pcchLeft = cchLeft;
3546 return pchWord;
3547 }
3548
3549 /* Second char. */
3550 ch = pchWord[1];
3551 if (KMK_CC_EVAL_IS_SPACE(ch))
3552 { /* maybe likely */ }
3553 else if ( ch == '\\'
3554 && pchWord[2] == pCompiler->chFirstEol)
3555 {
3556 pchWord += 1 + pCompiler->cchEscEolSeq;
3557 cchLeft -= 1 + pCompiler->cchEscEolSeq;
3558 pCompiler->iEscEol++;
3559 continue;
3560 }
3561 else
3562 {
3563 *pcchLeft = cchLeft - 1;
3564 return pchWord + 1;
3565 }
3566
3567 /* Third char. */
3568 ch = pchWord[2];
3569 if (KMK_CC_EVAL_IS_SPACE(ch))
3570 { /* maybe likely */ }
3571 else if ( ch == '\\'
3572 && pchWord[3] == pCompiler->chFirstEol
3573 && cchLeft >= 2 + pCompiler->cchEscEolSeq)
3574 {
3575 pchWord += 2 + pCompiler->cchEscEolSeq;
3576 cchLeft -= 2 + pCompiler->cchEscEolSeq;
3577 pCompiler->iEscEol++;
3578 continue;
3579 }
3580 else
3581 {
3582 *pcchLeft = cchLeft - 2;
3583 return pchWord + 2;
3584 }
3585
3586 /* Third char. */
3587 ch = pchWord[3];
3588 if (KMK_CC_EVAL_IS_SPACE(ch))
3589 {
3590 pchWord += 4;
3591 cchLeft -= 4;
3592 }
3593 else if ( ch == '\\'
3594 && cchLeft >= 3 + pCompiler->cchEscEolSeq
3595 && pchWord[4] == pCompiler->chFirstEol)
3596 {
3597 pchWord += 3 + pCompiler->cchEscEolSeq;
3598 cchLeft -= 3 + pCompiler->cchEscEolSeq;
3599 pCompiler->iEscEol++;
3600 }
3601 else
3602 {
3603 *pcchLeft = cchLeft - 3;
3604 return pchWord + 3;
3605 }
3606 }
3607
3608 /*
3609 * Simple loop for the final three chars.
3610 */
3611 while (cchLeft > 0)
3612 {
3613 /* First char. */
3614 char ch = *pchWord;
3615 if (KMK_CC_EVAL_IS_SPACE(ch))
3616 {
3617 pchWord += 1;
3618 cchLeft -= 1;
3619 }
3620 else if ( ch == '\\'
3621 && cchLeft > pCompiler->cchEolSeq
3622 && pchWord[1] == pCompiler->chFirstEol)
3623 {
3624 pchWord += pCompiler->cchEscEolSeq;
3625 cchLeft -= pCompiler->cchEscEolSeq;
3626 pCompiler->iEscEol++;
3627 }
3628 else
3629 break;
3630 }
3631
3632 *pcchLeft = cchLeft;
3633 return pchWord;
3634}
3635
3636
3637/**
3638 * Common path for space skipping worker functions when no escaped EOLs need
3639 * considering.
3640 *
3641 * @returns Points to the first non-space character or end of input.
3642 * @param pchWord The current position. There is some kind of char
3643 * @param cchLeft The current number of chars left to parse in the
3644 * current line.
3645 * @param pcchLeft Where to store the updated @a cchLeft value.
3646 * @param pCompiler The compiler instance data.
3647 */
3648static const char *kmk_cc_eval_skip_spaces_without_esc_eol(const char *pchWord, size_t cchLeft, size_t *pcchLeft,
3649 PKMKCCEVALCOMPILER pCompiler)
3650{
3651 /*
3652 * 4x loop unroll.
3653 */
3654 while (cchLeft >= 4)
3655 {
3656 if (KMK_CC_EVAL_IS_SPACE(pchWord[0]))
3657 {
3658 if (KMK_CC_EVAL_IS_SPACE(pchWord[1]))
3659 {
3660 if (KMK_CC_EVAL_IS_SPACE(pchWord[2]))
3661 {
3662 if (KMK_CC_EVAL_IS_SPACE(pchWord[3]))
3663 {
3664 pchWord += 4;
3665 cchLeft -= 4;
3666 }
3667 else
3668 {
3669 *pcchLeft = cchLeft - 3;
3670 return pchWord + 3;
3671 }
3672 }
3673 else
3674 {
3675 *pcchLeft = cchLeft - 2;
3676 return pchWord + 2;
3677 }
3678 }
3679 else
3680 {
3681 *pcchLeft = cchLeft - 1;
3682 return pchWord + 1;
3683 }
3684 }
3685 else
3686 {
3687 *pcchLeft = cchLeft;
3688 return pchWord;
3689 }
3690 }
3691
3692 /*
3693 * The last 3. Not entirely sure if this yield good code.
3694 */
3695 switch (cchLeft & 3)
3696 {
3697 case 3:
3698 if (!KMK_CC_EVAL_IS_SPACE(*pchWord))
3699 break;
3700 pchWord++;
3701 cchLeft--;
3702 case 2:
3703 if (!KMK_CC_EVAL_IS_SPACE(*pchWord))
3704 break;
3705 pchWord++;
3706 cchLeft--;
3707 case 1:
3708 if (!KMK_CC_EVAL_IS_SPACE(*pchWord))
3709 break;
3710 pchWord++;
3711 cchLeft--;
3712 case 0:
3713 break;
3714 }
3715
3716 *pcchLeft = cchLeft;
3717 return pchWord;
3718}
3719
3720
3721/**
3722 * Used to skip spaces after a word.
3723 *
3724 * We ASSUME that the first char is a space or that we've reached the end of the
3725 * string (a_cchLeft == 0).
3726 *
3727 * @param a_pCompiler The compiler instance data.
3728 * @param a_pchWord The current input position, this will be moved to
3729 * the start of the next word or end of the input.
3730 * @param a_cchLeft The number of chars left to parse. This will be
3731 * updated.
3732 */
3733#define KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(a_pCompiler, a_pchWord, a_cchLeft) \
3734 do { \
3735 /* Skip the first char which is known to be a space, end of line or end of input. */ \
3736 if ((a_cchLeft) > 0) \
3737 { \
3738 char const chSkipBlanksFirst = *(a_pchWord); \
3739 KMK_CC_ASSERT(KMK_CC_EVAL_IS_SPACE_AFTER_WORD(a_pCompiler, chSkipBlanksFirst, (a_pchWord)[1], a_cchLeft)); \
3740 if (chSkipBlanksFirst != '\\') \
3741 { \
3742 (a_pchWord) += 1; \
3743 (a_cchLeft) -= 1; \
3744 \
3745 /* Another space or escaped EOL? Then there are probably more then, so call worker function. */ \
3746 if ((a_cchLeft) > 0) \
3747 { \
3748 char const chSkipBlanksSecond = *(a_pchWord); \
3749 if (KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(chSkipBlanksSecond)) \
3750 (a_pchWord) = kmk_cc_eval_skip_spaces_after_word_slow(a_pchWord, &(a_cchLeft), \
3751 chSkipBlanksSecond, a_pCompiler); \
3752 } \
3753 } \
3754 else /* escape sequences can be complicated. */ \
3755 (a_pchWord) = kmk_cc_eval_skip_spaces_after_word_slow(a_pchWord, &(a_cchLeft), \
3756 chSkipBlanksFirst, a_pCompiler); \
3757 } \
3758 } while (0)
3759
3760/**
3761 * The slow path of KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD.
3762 *
3763 * This is called to handles escaped EOL sequences, as these can involve
3764 * multiple backslashes and therefore doesn't led themselves well to inlined
3765 * code.
3766 *
3767 * The other case this is used for is to handle more than once space, since it's
3768 * likely that when there are two there might be more. No point in inlining
3769 * that, better do some loop unrolling instead.
3770 *
3771 * @returns Points to the first non-space character or end of input.
3772 * @param pchWord The current position. There is some kind of char
3773 * @param pcchLeft Pointer to the cchLeft variable, this is both
3774 * input and output.
3775 * @param ch The current character.
3776 * @param pCompiler The compiler instance data.
3777 */
3778static const char *kmk_cc_eval_skip_spaces_after_word_slow(const char *pchWord, size_t *pcchLeft, char ch,
3779 PKMKCCEVALCOMPILER pCompiler)
3780{
3781 size_t cchLeft = *pcchLeft;
3782
3783 /*
3784 * It's all very simple when we don't have to consider escaped EOLs.
3785 */
3786 if (pCompiler->iEscEol >= pCompiler->cEscEols)
3787 {
3788 if (ch != '\\')
3789 {
3790 pchWord += 1;
3791 cchLeft -= 1;
3792 }
3793 else
3794 return pchWord;
3795 return kmk_cc_eval_skip_spaces_without_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler);
3796 }
3797
3798 /*
3799 * Skip the pending space or EOL found by the caller. We need to
3800 * confirm the EOL.
3801 *
3802 * Note! We only need to care about simple backslash+EOL sequences here
3803 * since we're either at the end of a validated word, or we've already
3804 * skipped one space. In the former case, someone else has already
3805 * validated the escape esequence, in the latter case multiple
3806 * backslashes would indicate a new word that that we should return.
3807 */
3808 if (ch != '\\')
3809 {
3810 pchWord += 1;
3811 cchLeft -= 1;
3812 }
3813 else if ( cchLeft >= pCompiler->cchEscEolSeq
3814 && pchWord[1] == pCompiler->chFirstEol)
3815 {
3816 KMK_CC_ASSERT(pCompiler->cchEolSeq == 1 || pchWord[2] == pCompiler->chSecondEol);
3817 pchWord += pCompiler->cchEscEolSeq;
3818 cchLeft -= pCompiler->cchEscEolSeq;
3819 pCompiler->iEscEol++;
3820
3821 if (pCompiler->iEscEol < pCompiler->cEscEols)
3822 { /* likely */ }
3823 else return kmk_cc_eval_skip_spaces_without_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler);
3824 }
3825 else
3826 return pchWord;
3827 return kmk_cc_eval_skip_spaces_with_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler);
3828}
3829
3830
3831/**
3832 * Skip zero or more spaces.
3833 *
3834 * This macro deals with a single space, if there are more or we're hittin some
3835 * possible escaped EOL sequence, work is deferred to a worker function.
3836 *
3837 * @param a_pCompiler The compiler state.
3838 * @param a_pchWord The current input position. Advanced past spaces.
3839 * @param a_cchLeft The amount of input left to parse. Will be updated.
3840 */
3841#define KMK_CC_EVAL_SKIP_SPACES(a_pCompiler, a_pchWord, a_cchLeft) \
3842 do { \
3843 if ((a_cchLeft) > 0) \
3844 { \
3845 char chSkipSpaces = *(a_pchWord); \
3846 if (KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(chSkipSpaces)) \
3847 { \
3848 if (chSkipSpaces != '\\') \
3849 { \
3850 (a_pchWord) += 1; \
3851 (a_cchLeft) -= 1; \
3852 chSkipSpaces = *(a_pchWord); \
3853 if (KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(chSkipSpaces)) \
3854 (a_pchWord) = kmk_cc_eval_skip_spaces_slow(a_pchWord, &(a_cchLeft), chSkipSpaces, a_pCompiler); \
3855 } \
3856 else \
3857 (a_pchWord) = kmk_cc_eval_skip_spaces_slow(a_pchWord, &(a_cchLeft), chSkipSpaces, a_pCompiler); \
3858 } \
3859 } \
3860 } while (0)
3861
3862
3863/**
3864 * Worker for KMK_CC_EVAL_SKIP_SPACES.
3865 *
3866 * @returns Points to the first non-space character or end of input.
3867 * @param pchWord The current position. There is some kind of char
3868 * @param pcchLeft Pointer to the cchLeft variable, this is both
3869 * input and output.
3870 * @param ch The current character.
3871 * @param pCompiler The compiler instance data.
3872 */
3873static const char *kmk_cc_eval_skip_spaces_slow(const char *pchWord, size_t *pcchLeft, char ch, PKMKCCEVALCOMPILER pCompiler)
3874{
3875 size_t cchLeft = *pcchLeft;
3876#ifdef KMK_CC_STRICT
3877 size_t offWordCcStrict = pchWord - pCompiler->pszContent;
3878#endif
3879 KMK_CC_ASSERT(cchLeft > 0);
3880 KMK_CC_ASSERT(cchLeft <= pCompiler->cchLine);
3881 KMK_CC_ASSERT(*pchWord == ch);
3882 KMK_CC_ASSERT(KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(ch));
3883 KMK_CC_ASSERT(offWordCcStrict >= pCompiler->offLine);
3884 KMK_CC_ASSERT(offWordCcStrict < pCompiler->offLine + pCompiler->cchLine);
3885 KMK_CC_ASSERT( pCompiler->iEscEol >= pCompiler->cEscEols
3886 || offWordCcStrict <= pCompiler->paEscEols[pCompiler->iEscEol].offEsc);
3887 KMK_CC_ASSERT( pCompiler->iEscEol >= pCompiler->cEscEols
3888 || pCompiler->iEscEol == 0
3889 || offWordCcStrict >= pCompiler->paEscEols[pCompiler->iEscEol - 1].offEol + pCompiler->cchEolSeq);
3890
3891 /*
3892 * If we don't need to consider escaped EOLs, things are much much simpler.
3893 */
3894 if (pCompiler->iEscEol >= pCompiler->cEscEols)
3895 {
3896 if (ch != '\\')
3897 {
3898 pchWord++;
3899 cchLeft--;
3900 }
3901 else
3902 return pchWord;
3903 return kmk_cc_eval_skip_spaces_without_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler);
3904 }
3905
3906 /*
3907 * Possible escaped EOL complications.
3908 */
3909 if (ch != '\\')
3910 {
3911 pchWord++;
3912 cchLeft--;
3913 }
3914 else
3915 {
3916 size_t cchSkip;
3917 size_t offWord;
3918 unsigned iEscEol = pCompiler->iEscEol;
3919 if (iEscEol >= pCompiler->cEscEols)
3920 return pchWord;
3921
3922 offWord = pchWord - pCompiler->pszContent;
3923 if (offWord < pCompiler->paEscEols[iEscEol].offEsc)
3924 return pchWord;
3925 KMK_CC_ASSERT(offWord == pCompiler->paEscEols[iEscEol].offEsc);
3926
3927 cchSkip = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq - offWord;
3928 pchWord += cchSkip;
3929 cchLeft -= cchSkip;
3930 pCompiler->iEscEol = ++iEscEol;
3931
3932 if (iEscEol < pCompiler->cEscEols)
3933 { /* likely */ }
3934 else return kmk_cc_eval_skip_spaces_without_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler);
3935 }
3936 return kmk_cc_eval_skip_spaces_with_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler);
3937}
3938
3939
3940/**
3941 * Skips to the end of a variable name.
3942 *
3943 * This may advance pCompiler->iEscEol.
3944 *
3945 * @returns Pointer to the first char after the variable name.
3946 * @param pCompiler The compiler state.
3947 * @param pchWord The current position. Must be at the start of the
3948 * variable name.
3949 * @param cchLeft The number of chars left to parse in the current line.
3950 * @param pcchLeft The to store the updated count of characters left to
3951 * parse.
3952 * @param pfPlain Where to store the plain variable name indicator.
3953 * Returns 0 if plain, and 1 if there are variable
3954 * references in it.
3955 */
3956static const char *kmk_cc_eval_skip_var_name(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft,
3957 size_t *pcchLeft, int *pfPlain)
3958{
3959 const char * const pszContent = pCompiler->pszContent;
3960 size_t off = pchWord - pszContent;
3961 size_t const offLineEnd = off + cchLeft;
3962 int fPlain = 1;
3963 unsigned iEscEol = pCompiler->iEscEol;
3964
3965 /* Check our expectations. */
3966 KMK_CC_ASSERT(cchLeft);
3967 KMK_CC_ASSERT(!KMK_CC_EVAL_IS_SPACE(*pchWord));
3968 KMK_CC_ASSERT(iEscEol <= pCompiler->cEscEols);
3969 KMK_CC_ASSERT( iEscEol >= pCompiler->cEscEols
3970 || off < pCompiler->paEscEols[iEscEol].offEol);
3971 KMK_CC_ASSERT(off >= (iEscEol == 0 ? pCompiler->offLine : pCompiler->paEscEols[iEscEol - 1].offEol + pCompiler->cchEolSeq));
3972
3973 /*
3974 * The outer loop parses plain text. Variable expansion ($) is handled
3975 * by an inner loop.
3976 */
3977 while (off < offLineEnd)
3978 {
3979 char ch = pszContent[off];
3980 if (!KMK_CC_EVAL_IS_SPACE_DOLLAR_OR_SLASH(ch))
3981 off++;
3982 else if (KMK_CC_EVAL_IS_SPACE(ch))
3983 break;
3984 else if (ch == '$')
3985 {
3986 off++;
3987 if (off < offLineEnd)
3988 {
3989 char const chOpen = pszContent[off];
3990 if (chOpen == '(' || chOpen == '{')
3991 {
3992 /*
3993 * Got a $(VAR) or ${VAR} to deal with here. This may
3994 * include nested variable references and span multiple
3995 * lines (at least for function calls).
3996 *
3997 * We scan forward till we've found the corresponding
3998 * closing parenthesis, considering any open parentheses
3999 * of the same kind as worth counting, even if there are
4000 * no dollar preceeding them, just like GNU make does.
4001 */
4002 size_t const offStart = off - 1;
4003 char const chClose = chOpen == '(' ? ')' : '}';
4004 unsigned cOpen = 1;
4005 off++;
4006 for (;;)
4007 {
4008 if (off < offLineEnd)
4009 {
4010 ch = pszContent[off];
4011 if (!(KMK_CC_EVAL_IS_PAREN_OR_SLASH(ch)))
4012 off++;
4013 else
4014 {
4015 off++;
4016 if (ch == chClose)
4017 {
4018 if (--cOpen == 0)
4019 break;
4020 }
4021 else if (ch == chOpen)
4022 cOpen++;
4023 else if ( ch == '\\'
4024 && iEscEol < pCompiler->cEscEols
4025 && off == pCompiler->paEscEols[iEscEol].offEsc)
4026 {
4027 off = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq;
4028 pCompiler->iEscEol = ++iEscEol;
4029 }
4030 }
4031 }
4032 else if (cOpen == 1)
4033 kmk_cc_eval_fatal(pCompiler, &pszContent[offStart],
4034 "Variable reference is missing '%c'", chClose);
4035 else
4036 kmk_cc_eval_fatal(pCompiler, &pszContent[offStart],
4037 "%u variable references are missing '%c'", cOpen, chClose);
4038 }
4039 }
4040 /* Single char variable name. */
4041 else if (!KMK_CC_EVAL_IS_SPACE(chOpen))
4042 { /* likely */ }
4043 else
4044 kmk_cc_eval_fatal(pCompiler, &pszContent[off], "Expected variable name after '$', not end of line");
4045 }
4046 else
4047 kmk_cc_eval_fatal(pCompiler, &pszContent[off], "Expected variable name after '$', not end of line");
4048 fPlain = 0;
4049 }
4050 /* Deal with potential escaped EOL. */
4051 else if ( ch != '\\'
4052 || iEscEol >= pCompiler->cEscEols
4053 || off != pCompiler->paEscEols[iEscEol].offEsc )
4054 off++;
4055 else
4056 break;
4057 }
4058
4059 *pcchLeft = offLineEnd - off;
4060 *pfPlain = fPlain;
4061 return &pszContent[off];
4062}
4063
4064
4065#if 0 /* unused atm */
4066/**
4067 * Prepares for copying a command line.
4068 *
4069 * The current version of this code will not modify any of the paEscEols
4070 * entries, unlike our kmk_cc_eval_prep_normal_line sibling function.
4071 *
4072 * @returns The number of chars that will be copied by
4073 * kmk_cc_eval_copy_prepped_command_line().
4074 * @param pCompiler The compiler instance data.
4075 * @param pchLeft Pointer to the first char to copy from the current line.
4076 * This does not have to the start of a word.
4077 * @param cchLeft The number of chars left on the current line starting at
4078 * @a pchLeft.
4079 */
4080static size_t kmk_cc_eval_prep_command_line(PKMKCCEVALCOMPILER pCompiler, const char * const pchLeft, size_t cchLeft)
4081{
4082 size_t cchRet;
4083 unsigned iEscEol = pCompiler->iEscEol;
4084 unsigned const cEscEols = pCompiler->cEscEols;
4085
4086 KMK_CC_ASSERT(cchLeft > 0);
4087 KMK_CC_ASSERT(iEscEol <= cEscEols);
4088
4089 if (iEscEol >= cEscEols)
4090 {
4091 /*
4092 * No escaped EOLs left, dead simple.
4093 */
4094 cchRet = cchLeft;
4095 }
4096 else
4097 {
4098 /*
4099 * Compared to the normal prepping of a line, this is actually
4100 * really simple. We need to account for two kind of conversions:
4101 * - One leading tab is skipped after escaped EOL.
4102 * - Convert EOL to LF.
4103 */
4104 const char * const pszContent = pCompiler->pszContent;
4105 size_t const cchEolSeq = pCompiler->cchEolSeq;
4106
4107#ifdef KMK_CC_STRICT
4108 size_t const offLeft = pchLeft - pszContent;
4109 KMK_CC_ASSERT(offLeft + cchLeft <= pCompiler->offLine + pCompiler->cchLine);
4110 KMK_CC_ASSERT(offLeft + cchLeft <= pCompiler->cchContent);
4111 KMK_CC_ASSERT(offLeft < pCompiler->paEscEols[iEscEol].offEsc);
4112 KMK_CC_ASSERT(offLeft >= (iEscEol ? pCompiler->paEscEols[cEscEols - 1].offEol + pCompiler->cchEolSeq : pCompiler->offLine));
4113#endif
4114
4115 cchRet = cchLeft;
4116 if (cchEolSeq > 1)
4117 cchRet -= (cchEolSeq - 1) * cEscEols;
4118 do
4119 {
4120 if (pszContent[pCompiler->paEscEols[cchEolSeq].offEol])
4121 cchRet--;
4122 iEscEol++;
4123 } while (iEscEol < cEscEols);
4124 }
4125 return cchRet;
4126}
4127
4128
4129/**
4130 * Copies a command line to the buffer @a pszDst points to.
4131 *
4132 * Must only be used immediately after kmk_cc_eval_prep_command_line().
4133 *
4134 * @returns
4135 * @param pCompiler The compiler instance data.
4136 * @param pchLeft Pointer to the first char to copy from the current line.
4137 * This does not have to the start of a word.
4138 * @param cchPrepped The return value of kmk_cc_eval_prep_command_line().
4139 * @param pszDst The destination buffer, must be at least @a cchPrepped
4140 * plus one (terminator) char big.
4141 */
4142static void kmk_cc_eval_copy_prepped_command_line(PKMKCCEVALCOMPILER pCompiler, const char *pchLeft,
4143 size_t cchPrepped, char *pszDst)
4144{
4145 unsigned iEscEol = pCompiler->iEscEol;
4146 unsigned const cEscEols = pCompiler->cEscEols;
4147 if (iEscEol >= cEscEols)
4148 {
4149 /* Single line. */
4150 memcpy(pszDst, pchLeft, cchPrepped);
4151 pszDst[cchPrepped] = '\0';
4152 }
4153 else
4154 {
4155 /* Multiple lines with normalized EOL and maybe one stripped leading TAB. */
4156 char * const pszDstStart = pszDst;
4157 const char * const pszContent = pCompiler->pszContent;
4158 size_t const cchEolSeq = pCompiler->cchEolSeq;
4159 size_t offLeft = pchLeft - pCompiler->pszContent;
4160 size_t cchCopy;
4161
4162 do
4163 {
4164 size_t offEol = pCompiler->paEscEols[iEscEol].offEsc;
4165 cchCopy = offEol - offLeft;
4166 KMK_CC_ASSERT(offEol >= offLeft);
4167
4168 memcpy(pszDst, &pszContent[offLeft], cchCopy);
4169 pszDst += cchCopy;
4170 *pszDst += '\n';
4171
4172 offLeft = offEol + cchEolSeq;
4173 if (pszContent[offLeft] == '\t')
4174 offLeft++;
4175 } while (iEscEol < cEscEols);
4176
4177 cchCopy = cchPrepped - (pszDst - pszDstStart);
4178 KMK_CC_ASSERT(cchCopy <= cchPrepped);
4179 memcpy(pszDst, &pszContent[offLeft], cchCopy);
4180 pszDst += cchCopy;
4181
4182 *pszDst = '\0';
4183 KMK_CC_ASSERT(pszDst == &pszDstStart[cchPrepped]);
4184 }
4185}
4186#endif /* unused atm */
4187
4188
4189/**
4190 * Helper for ensuring that we've got sufficient number of words allocated.
4191 */
4192#define KMK_CC_EVAL_ENSURE_WORDS(a_pCompiler, a_cRequiredWords) \
4193 do { \
4194 if ((a_cRequiredWords) < (a_pCompiler)->cWordsAllocated) \
4195 { /* likely */ } \
4196 else \
4197 { \
4198 unsigned cEnsureWords = ((a_cRequiredWords) + 3 /*15*/) & ~(unsigned)3/*15*/; \
4199 KMK_CC_ASSERT((a_cRequiredWords) < 0x8000); \
4200 (a_pCompiler)->paWords = (PKMKCCEVALWORD)xrealloc((a_pCompiler)->paWords, \
4201 cEnsureWords * sizeof((a_pCompiler)->paWords)[0]); \
4202 } \
4203 } while (0)
4204
4205
4206/**
4207 * Word parser helper function for dealing with dollars, simple variant that
4208 * doesn't need to take multiple lines into account.
4209 *
4210 * @returns New word length placing us after the
4211 * @param pCompiler The compiler state.
4212 * @param cchWord Offset of the dollar into pchWord.
4213 * @param pchWord The word we're currently parsing.
4214 * @param cchLeft How much we've got left to parse.
4215 */
4216K_INLINE size_t kmk_cc_eval_parse_along_dollar_simple(PKMKCCEVALCOMPILER pCompiler, size_t cchWord,
4217 const char *pchWord, size_t cchLeft)
4218{
4219 const size_t cchStart = cchWord;
4220 cchWord++;
4221 if (cchWord < cchLeft)
4222 {
4223 /*
4224 * Got a $(VAR) or ${VAR} to deal with here. This may include nested variable
4225 * references and span multiple lines (at least for function calls).
4226 *
4227 * We scan forward till we've found the corresponding closing parenthesis,
4228 * considering any open parentheses of the same kind as worth counting, even
4229 * if there are no dollar preceeding them, just like GNU make does.
4230 *
4231 * We leave the other parenthesis type to the expansion compiler to deal with.
4232 */
4233 unsigned cOpens = 1;
4234 char const chOpen = pchWord[cchWord++];
4235 if (chOpen == '(')
4236 {
4237 for (;;)
4238 {
4239 if (cchWord < cchLeft)
4240 {
4241 char const ch = pchWord[cchWord++];
4242 if (!KMK_CC_EVAL_IS_PAREN_OR_SLASH(ch))
4243 { /* likely */ }
4244 else if (ch == ')')
4245 {
4246 if (--cOpens == 0)
4247 return cchWord;
4248 }
4249 else if (ch == '(')
4250 cOpens++;
4251 }
4252 else
4253 break;
4254 }
4255 }
4256 else if (chOpen == '{')
4257 {
4258 for (;;)
4259 {
4260 if (cchWord < cchLeft)
4261 {
4262 char const ch = pchWord[cchWord++];
4263 if (!KMK_CC_EVAL_IS_PAREN_OR_SLASH(ch))
4264 { /* likely */ }
4265 else if (ch == '}')
4266 {
4267 if (--cOpens == 0)
4268 return cchWord;
4269 }
4270 else if (ch == '{')
4271 cOpens++;
4272 }
4273 else
4274 break;
4275 }
4276 }
4277 else
4278 return cchWord;
4279
4280 /* Unterminated. */
4281 if (cOpens == 1)
4282 kmk_cc_eval_fatal(pCompiler, &pchWord[cchStart],
4283 "Variable reference is missing '%c'", chOpen == '(' ? ')' : '}');
4284 else
4285 kmk_cc_eval_fatal(pCompiler, &pchWord[cchStart],
4286 "%u variable references are missing '%c'", cOpens, chOpen == '(' ? ')' : '}');
4287 }
4288 else
4289 kmk_cc_eval_warn(pCompiler, &pchWord[cchWord - 1], "found '$' at end of line");
4290 return cchWord;
4291}
4292
4293
4294/**
4295 * Word parser helper function for dealing with dollars, complicated variant
4296 * that takes escaped EOLs into account.
4297 *
4298 * @returns New word length placing us after the
4299 * @param pCompiler The compiler state.
4300 * @param cchWord Offset of the dollar into pchWord.
4301 * @param pchWord The word we're currently parsing.
4302 * @param cchLeft How much we've got left to parse.
4303 */
4304static size_t kmk_cc_eval_parse_along_dollar_esc_eol(PKMKCCEVALCOMPILER pCompiler, size_t cchWord,
4305 const char *pchWord, size_t cchLeft)
4306{
4307 const size_t cchStart = cchWord;
4308 cchWord++;
4309 if (cchWord < cchLeft)
4310 {
4311 /*
4312 * Got a $(VAR) or ${VAR} to deal with here. This may include nested variable
4313 * references and span multiple lines (at least for function calls).
4314 *
4315 * We scan forward till we've found the corresponding closing parenthesis,
4316 * considering any open parentheses of the same kind as worth counting, even
4317 * if there are no dollar preceeding them, just like GNU make does.
4318 *
4319 * We leave the other parenthesis type to the expansion compiler to deal with.
4320 */
4321 unsigned cOpens = 1;
4322 char const chOpen = pchWord[cchWord++];
4323 if (chOpen == '(')
4324 {
4325 for (;;)
4326 {
4327 if (cchWord < cchLeft)
4328 {
4329 char const ch = pchWord[cchWord++];
4330 if (!KMK_CC_EVAL_IS_PAREN_OR_SLASH(ch))
4331 { /* likely */ }
4332 else if (ch == ')')
4333 {
4334 if (--cOpens == 0)
4335 return cchWord;
4336 }
4337 else if (ch == '(')
4338 cOpens++;
4339 else if (ch == '\\')
4340 {
4341 unsigned const iEscEol = pCompiler->iEscEol;
4342 if ( iEscEol < pCompiler->cEscEols
4343 && (size_t)(&pchWord[cchWord] - pCompiler->pszContent) == pCompiler->paEscEols[iEscEol].offEsc)
4344 {
4345 cchWord += pCompiler->paEscEols[iEscEol].offEol
4346 - pCompiler->paEscEols[iEscEol].offEsc
4347 + pCompiler->cchEolSeq;
4348 pCompiler->iEscEol = iEscEol + 1;
4349 }
4350 }
4351 }
4352 else
4353 break;
4354 }
4355 }
4356 else if (chOpen == '{')
4357 {
4358 for (;;)
4359 {
4360 if (cchWord < cchLeft)
4361 {
4362 char const ch = pchWord[cchWord++];
4363 if (!KMK_CC_EVAL_IS_PAREN_OR_SLASH(ch))
4364 { /* likely */ }
4365 else if (ch == '}')
4366 {
4367 if (--cOpens == 0)
4368 return cchWord;
4369 }
4370 else if (ch == '{')
4371 cOpens++;
4372 else if (ch == '\\')
4373 {
4374 unsigned const iEscEol = pCompiler->iEscEol;
4375 if ( iEscEol < pCompiler->cEscEols
4376 && (size_t)(&pchWord[cchWord] - pCompiler->pszContent) == pCompiler->paEscEols[iEscEol].offEsc)
4377 {
4378 cchWord += pCompiler->paEscEols[iEscEol].offEol
4379 - pCompiler->paEscEols[iEscEol].offEsc
4380 + pCompiler->cchEolSeq;
4381 pCompiler->iEscEol = iEscEol + 1;
4382 }
4383 }
4384 }
4385 else
4386 break;
4387 }
4388 }
4389 else
4390 return cchWord;
4391
4392 /* Unterminated. */
4393 if (cOpens == 1)
4394 kmk_cc_eval_fatal(pCompiler, &pchWord[cchStart],
4395 "Variable reference is missing '%c'", chOpen == '(' ? ')' : '}');
4396 else
4397 kmk_cc_eval_fatal(pCompiler, &pchWord[cchStart],
4398 "%u variable references are missing '%c'", cOpens, chOpen == '(' ? ')' : '}');
4399 }
4400 else
4401 kmk_cc_eval_warn(pCompiler, &pchWord[cchWord - 1], "found '$' at end of line");
4402 return cchWord;
4403}
4404
4405
4406/**
4407 * Parses the remainder of the line into simple words.
4408 *
4409 * The resulting words are classified as either kKmkCcEvalToken_WordPlain or
4410 * kKmkCcEvalToken_WordWithDollar.
4411 *
4412 * @returns Number of words.
4413 * @param pCompiler The compiler state.
4414 * @param pchWord Where to start, we expect this to be at a word.
4415 * @param cchLeft The number of chars left to parse on this line.
4416 * This is expected to be non-zero.
4417 */
4418static unsigned kmk_cc_eval_parse_words(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
4419{
4420 unsigned iEscEol = pCompiler->iEscEol;
4421 unsigned cEscEols = pCompiler->cEscEols;
4422 unsigned cWords = 0;
4423
4424 /* Precoditions. */
4425 KMK_CC_ASSERT(cchLeft > 0);
4426 KMK_CC_ASSERT(!KMK_CC_EVAL_IS_SPACE(*pchWord));
4427
4428 /*
4429 * If we don't have to deal with escaped EOLs, the find-end-of word search
4430 * becomes a little bit simpler. Since this function will be used a lot
4431 * for simple lines with single words, this could maybe save a nano second
4432 * or two.
4433 */
4434 if (iEscEol >= cEscEols)
4435 {
4436 do
4437 {
4438 size_t cchSkipAfter = 0;
4439 size_t cchWord = 0;
4440 KMKCCEVALTOKEN enmToken = kKmkCcEvalToken_WordPlain;
4441
4442 /* Find the end of the current word. */
4443 while (cchWord < cchLeft)
4444 {
4445 char ch = pchWord[cchWord];
4446 if (!KMK_CC_EVAL_IS_SPACE_OR_DOLLAR(ch))
4447 cchWord++;
4448 else if (ch == '$')
4449 {
4450 enmToken = kKmkCcEvalToken_WordWithDollar;
4451 cchWord = kmk_cc_eval_parse_along_dollar_simple(pCompiler, cchWord, pchWord, cchLeft);
4452 }
4453 else
4454 break;
4455 }
4456
4457 /* Add the word. */
4458 KMK_CC_EVAL_ENSURE_WORDS(pCompiler, cWords + 1);
4459 pCompiler->paWords[cWords].pchWord = pchWord;
4460 pCompiler->paWords[cWords].cchWord = cchWord;
4461 pCompiler->paWords[cWords].enmToken = enmToken;
4462 cWords++;
4463
4464 /* Skip the work and any trailing blanks. */
4465 cchWord += cchSkipAfter;
4466 pchWord += cchWord;
4467 cchLeft -= cchWord;
4468 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4469 } while (cchLeft > 0);
4470 }
4471 /*
4472 * Have to deal with escaped EOLs.
4473 */
4474 else
4475 {
4476 const char *pszContent = pCompiler->pszContent;
4477 do
4478 {
4479 size_t cchSkipAfter = 0;
4480 size_t cchWord = 0;
4481 KMKCCEVALTOKEN enmToken = kKmkCcEvalToken_WordPlain;
4482
4483 /* Find the end of the current word. */
4484 while (cchWord < cchLeft)
4485 {
4486 char ch = pchWord[cchWord];
4487 if (!KMK_CC_EVAL_IS_SPACE_DOLLAR_OR_SLASH(ch))
4488 cchWord++;
4489 else if (ch == '$')
4490 {
4491 enmToken = kKmkCcEvalToken_WordWithDollar;
4492 cchWord = kmk_cc_eval_parse_along_dollar_esc_eol(pCompiler, cchWord, pchWord, cchLeft);
4493 }
4494 else if (ch != '\\')
4495 break;
4496 else if ((size_t)(&pchWord[cchWord] - pszContent) != pCompiler->paEscEols[iEscEol].offEsc)
4497 cchWord++;
4498 else
4499 {
4500 cchSkipAfter = pCompiler->paEscEols[iEscEol].offEol - pCompiler->paEscEols[iEscEol].offEsc
4501 + pCompiler->cchEolSeq;
4502 iEscEol++;
4503 break;
4504 }
4505 }
4506
4507 /* Add the word. */
4508 KMK_CC_EVAL_ENSURE_WORDS(pCompiler, cWords + 1);
4509 pCompiler->paWords[cWords].pchWord = pchWord;
4510 pCompiler->paWords[cWords].cchWord = cchWord;
4511 pCompiler->paWords[cWords].enmToken = enmToken;
4512 cWords++;
4513
4514 /* Skip the work and any trailing blanks. */
4515 cchWord += cchSkipAfter;
4516 pchWord += cchWord;
4517 cchLeft -= cchWord;
4518 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4519 } while (cchLeft > 0);
4520 }
4521 pCompiler->cWords = cWords;
4522 return cWords;
4523}
4524
4525
4526/**
4527 * Parses the remainder of the line into target words.
4528 *
4529 * The resulting words are classified as either kKmkCcEvalToken_WordPlain or
4530 * kKmkCcEvalToken_WordWithDollar.
4531 *
4532 * @returns Number of words.
4533 * @param pCompiler The compiler state.
4534 * @param pchWord Where to start, we expect this to be at a word.
4535 * @param cchLeft The number of chars left to parse on this line.
4536 * This is expected to be non-zero.
4537 */
4538static unsigned kmk_cc_eval_parse_recipe_words(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
4539{
4540 unsigned iEscEol = pCompiler->iEscEol;
4541 unsigned cEscEols = pCompiler->cEscEols;
4542 unsigned cWords = 0;
4543
4544 /* Precoditions. */
4545 KMK_CC_ASSERT(cchLeft > 0);
4546 KMK_CC_ASSERT(!KMK_CC_EVAL_IS_SPACE(*pchWord));
4547
4548 /*
4549 * If we don't have to deal with escaped EOLs, the find-end-of word search
4550 * becomes a little bit simpler. Since this function will be used a lot
4551 * for simple lines with single words, this could maybe save a nano second
4552 * or two.
4553 */
4554 if (iEscEol >= cEscEols)
4555 {
4556 do
4557 {
4558 size_t cchSkipAfter = 0;
4559 size_t cchWord = 0;
4560 KMKCCEVALTOKEN enmToken = kKmkCcEvalToken_WordPlain;
4561
4562 /* Find the end of the current word. */
4563 while (cchWord < cchLeft)
4564 {
4565 char ch = pchWord[cchWord];
4566 if (!KMK_CC_EVAL_IS_SPACE_OR_DOLLAR(ch))
4567 cchWord++;
4568 else if (ch == '$')
4569 {
4570 enmToken = kKmkCcEvalToken_WordWithDollar;
4571 cchWord = kmk_cc_eval_parse_along_dollar_simple(pCompiler, cchWord, pchWord, cchLeft);
4572 }
4573 else
4574 break;
4575 }
4576
4577 /* Add the word. */
4578 KMK_CC_EVAL_ENSURE_WORDS(pCompiler, cWords + 1);
4579 pCompiler->paWords[cWords].pchWord = pchWord;
4580 pCompiler->paWords[cWords].cchWord = cchWord;
4581 pCompiler->paWords[cWords].enmToken = enmToken;
4582 cWords++;
4583
4584 /* Skip the work and any trailing blanks. */
4585 cchWord += cchSkipAfter;
4586 pchWord += cchWord;
4587 cchLeft -= cchWord;
4588 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4589 } while (cchLeft > 0);
4590 }
4591 /*
4592 * Have to deal with escaped EOLs.
4593 */
4594 else
4595 {
4596 const char *pszContent = pCompiler->pszContent;
4597 do
4598 {
4599 size_t cchSkipAfter = 0;
4600 size_t cchWord = 0;
4601 KMKCCEVALTOKEN enmToken = kKmkCcEvalToken_WordPlain;
4602
4603 /* Find the end of the current word. */
4604 while (cchWord < cchLeft)
4605 {
4606 char ch = pchWord[cchWord];
4607 if (!KMK_CC_EVAL_IS_SPACE_DOLLAR_OR_SLASH(ch))
4608 cchWord++;
4609 else if (ch == '$')
4610 {
4611 enmToken = kKmkCcEvalToken_WordWithDollar;
4612 cchWord = kmk_cc_eval_parse_along_dollar_esc_eol(pCompiler, cchWord, pchWord, cchLeft);
4613 }
4614 else if (ch != '\\')
4615 break;
4616 else if ((size_t)(&pchWord[cchWord] - pszContent) != pCompiler->paEscEols[iEscEol].offEsc)
4617 cchWord++;
4618 else
4619 {
4620 cchSkipAfter = pCompiler->paEscEols[iEscEol].offEol - pCompiler->paEscEols[iEscEol].offEsc
4621 + pCompiler->cchEolSeq;
4622 iEscEol++;
4623 break;
4624 }
4625 }
4626
4627 /* Add the word. */
4628 KMK_CC_EVAL_ENSURE_WORDS(pCompiler, cWords + 1);
4629 pCompiler->paWords[cWords].pchWord = pchWord;
4630 pCompiler->paWords[cWords].cchWord = cchWord;
4631 pCompiler->paWords[cWords].enmToken = enmToken;
4632 cWords++;
4633
4634 /* Skip the work and any trailing blanks. */
4635 cchWord += cchSkipAfter;
4636 pchWord += cchWord;
4637 cchLeft -= cchWord;
4638 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4639 } while (cchLeft > 0);
4640 }
4641 pCompiler->cWords = cWords;
4642 return cWords;
4643}
4644
4645
4646
4647
4648/**
4649 * Gather string from segments and optional space insertion trick.
4650 *
4651 * @param pszDst The destination buffer.
4652 * @param paSegs The source segments.
4653 * @param cSegs The number of segments.
4654 * @param cchDstPrepped The size of pszDst, excluding the terminator.
4655 */
4656static void kmk_cc_eval_strcpyv(char *pszDst, PCKMKCCEVALSTRCPYSEG paSegs, unsigned cSegs, size_t cchDstPrepped)
4657{
4658 const char *pszDstStart = pszDst;
4659 unsigned iSeg = 0;
4660 while (iSeg < cSegs)
4661 {
4662 size_t cchToCopy;
4663 if (paSegs[iSeg].cchSrcAndPrependSpace >= 0)
4664 cchToCopy = paSegs[iSeg].cchSrcAndPrependSpace;
4665 else
4666 {
4667 cchToCopy = -paSegs[iSeg].cchSrcAndPrependSpace;
4668 *pszDst++ = ' ';
4669 }
4670
4671 memcpy(pszDst, paSegs[iSeg].pchSrc, cchToCopy);
4672 pszDst += cchToCopy;
4673
4674 iSeg++;
4675 }
4676 *pszDst = '\0';
4677 KMK_CC_ASSERT(pszDst == &pszDstStart[cchDstPrepped]); K_NOREF(pszDstStart); K_NOREF(cchDstPrepped);
4678}
4679
4680
4681/**
4682 * Allocate a byte buffer and ocpy the prepared string segments into it.
4683 *
4684 * The caller must call kmk_cc_block_realign!
4685 *
4686 * @returns Pointer to the duplicated string.
4687 * @param pCompiler The compiler instance data.
4688 * @param cchPrepped The length of the prepped string segments.
4689 */
4690static char *kmk_cc_eval_strdup_prepped(PKMKCCEVALCOMPILER pCompiler, size_t cchPrepped)
4691{
4692 char *pszCopy = kmk_cc_block_byte_alloc(pCompiler->ppBlockTail, cchPrepped + 1);
4693 kmk_cc_eval_strcpyv(pszCopy, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, cchPrepped);
4694 return pszCopy;
4695}
4696
4697
4698/**
4699 * Strip trailing spaces from prepped copy
4700 *
4701 * @param paSegs The segments to strip trailing chars from.
4702 * @param pcSegs The number of segments (in/out).
4703 * @param pcchDstPrepped The total number of chars prepped (in/out).
4704 */
4705static void kmk_cc_eval_strip_right_v(PKMKCCEVALSTRCPYSEG paSegs, unsigned *pcSegs, size_t *pcchDstPrepped)
4706{
4707 /*
4708 * Work our way thru the segments, from the end obviously.
4709 */
4710 size_t cchDstPrepped = *pcchDstPrepped;
4711 unsigned cSegs = *pcSegs;
4712 while (cSegs > 0)
4713 {
4714 unsigned iSeg = cSegs - 1;
4715 const char *pszSrc = paSegs[iSeg].pchSrc;
4716 size_t cchSrc = paSegs[iSeg].cchSrcAndPrependSpace >= 0
4717 ? paSegs[iSeg].cchSrcAndPrependSpace : -paSegs[iSeg].cchSrcAndPrependSpace;
4718 if (cchSrc)
4719 {
4720 /*
4721 * Check for trailing spaces.
4722 */
4723 size_t cchSrcOrg;
4724 if (!KMK_CC_EVAL_IS_SPACE(pszSrc[cchSrc - 1]))
4725 {
4726 /* Special case: No trailing spaces at all. No need to update
4727 input/output variables. */
4728 if (cSegs == *pcSegs)
4729 return;
4730 break;
4731 }
4732
4733 /* Skip the rest of the trailing spaces. */
4734 cchSrcOrg = cchSrc;
4735 do
4736 cchSrc--;
4737 while (cchSrc > 0 && KMK_CC_EVAL_IS_SPACE(pszSrc[cchSrc - 1]));
4738
4739 if (cchSrc > 0)
4740 {
4741 /*
4742 * There are non-space chars in this segment. So, update the
4743 * segment and total char count and we're done.
4744 */
4745 cchDstPrepped -= cchSrcOrg - cchSrc;
4746 if (paSegs[iSeg].cchSrcAndPrependSpace < 0)
4747 paSegs[iSeg].cchSrcAndPrependSpace = -(ssize_t)cchSrc;
4748 else
4749 paSegs[iSeg].cchSrcAndPrependSpace = cchSrc;
4750 break;
4751 }
4752
4753 /*
4754 * Skip the whole segment.
4755 */
4756 cchDstPrepped -= cchSrcOrg + (paSegs[iSeg].cchSrcAndPrependSpace < 0);
4757 }
4758 cSegs--;
4759 }
4760 *pcchDstPrepped = cchDstPrepped;
4761 *pcSegs = cSegs;
4762}
4763
4764/**
4765 * Helper for ensuring that we've got sufficient number of string copy segments.
4766 */
4767#define KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(a_pCompiler, a_cRequiredSegs) \
4768 do { \
4769 if ((a_cRequiredSegs) < (a_pCompiler)->cStrCopySegsAllocated) \
4770 { /* likely */ } \
4771 else \
4772 { \
4773 unsigned cEnsureSegs = ((a_cRequiredSegs) + 3 /*15*/) & ~(unsigned)3/*15*/; \
4774 KMK_CC_ASSERT((a_cRequiredSegs) < 0x8000); \
4775 (a_pCompiler)->paStrCopySegs = (PKMKCCEVALSTRCPYSEG)xmalloc(cEnsureSegs * sizeof((a_pCompiler)->paStrCopySegs)[0]); \
4776 } \
4777 } while (0)
4778
4779
4780/**
4781 * Prepares for copying a normal line, extended version.
4782 *
4783 * This does not assume that we start on a word, it can handle any starting
4784 * character. It can also prepare partial copies.
4785 *
4786 * In addition to the returned information, this will store instruction in
4787 * paEscEols for the following kmk_cc_eval_strcpyv() call.
4788 *
4789 * This will advance pCompiler->iEscEol, so that it's possible to use the common
4790 * macros and helpers for parsing what comes afterwards.
4791 *
4792 * @returns The number of chars that will be copied by kmk_cc_eval_strcpyv().
4793 * @param pCompiler The compiler instance data.
4794 * @param pchWord Pointer to the first char to copy from the
4795 * current line. This must be the start of a
4796 * word.
4797 * @param cchLeft The number of chars left on the current line
4798 * starting at @a pchWord.
4799 */
4800static size_t kmk_cc_eval_prep_normal_line_ex(PKMKCCEVALCOMPILER pCompiler, const char * const pchWord, size_t cchLeft)
4801{
4802 size_t cchRet;
4803 unsigned iEscEol = pCompiler->iEscEol;
4804 unsigned const cEscEols = pCompiler->cEscEols;
4805
4806 KMK_CC_ASSERT(iEscEol <= cEscEols);
4807
4808 if (cchLeft > 0)
4809 {
4810 /*
4811 * If there are no escaped EOLs left, just copy exactly
4812 * what was passed in.
4813 */
4814 if (iEscEol >= cEscEols)
4815 {
4816 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, 1);
4817 pCompiler->cStrCopySegs = 1;
4818 pCompiler->paStrCopySegs[0].pchSrc = pchWord;
4819 pCompiler->paStrCopySegs[0].cchSrcAndPrependSpace = cchRet = cchLeft;
4820 }
4821 /*
4822 * Ok, we have to deal with escaped EOLs and do the proper
4823 * replacement of escaped newlines with space. The deal is that we
4824 * collaps all whitespace before and after one or more newlines into a
4825 * single space. (FreeBSD make does this differently, by the by.)
4826 */
4827 else
4828 {
4829 const char * const pszContent = pCompiler->pszContent;
4830 size_t offWord = pchWord - pCompiler->pszContent;
4831 size_t const offLineEnd = offWord + cchLeft; /* Note! Not necessarily end of line.*/
4832 size_t offEsc;
4833 size_t fPendingSpace = 0;
4834 unsigned cSegs = 0;
4835 size_t cchSeg;
4836
4837 /* Go nuts checking our preconditions here. */
4838 KMK_CC_ASSERT(offWord >= pCompiler->offLine);
4839 KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->offLine + pCompiler->cchLine);
4840 KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->cchContent);
4841 KMK_CC_ASSERT(offWord <= pCompiler->paEscEols[iEscEol].offEsc);
4842 KMK_CC_ASSERT(offWord >= (iEscEol ? pCompiler->paEscEols[cEscEols - 1].offEol + pCompiler->cchEolSeq
4843 : pCompiler->offLine));
4844 KMK_CC_ASSERT(offWord < offLineEnd);
4845
4846 /* Make sure we've got more than enough segments to fill in. */
4847 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, cEscEols - iEscEol + 2);
4848
4849 /*
4850 * All but the last line.
4851 */
4852 cchRet = 0;
4853 do
4854 {
4855 KMK_CC_ASSERT(offWord < offLineEnd);
4856 offEsc = pCompiler->paEscEols[iEscEol].offEsc;
4857 if (offWord < offEsc)
4858 {
4859 /* Strip trailing spaces. */
4860 while (offEsc > offWord && KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1]))
4861 offEsc--;
4862 cchSeg = offEsc - offWord;
4863 if (cchSeg)
4864 {
4865 /* Add segment. */
4866 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord];
4867 if (offEsc < offLineEnd)
4868 {
4869 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace
4870 ? -(ssize_t)cchSeg : (ssize_t)cchSeg;
4871 cchRet += cchSeg + fPendingSpace;
4872 cSegs += 1;
4873 fPendingSpace = 1;
4874 }
4875 else
4876 {
4877 cchSeg = offLineEnd - offWord;
4878 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace
4879 ? -(ssize_t)cchSeg : (ssize_t)cchSeg;
4880 pCompiler->cStrCopySegs = cSegs + 1;
4881 pCompiler->iEscEol = iEscEol;
4882 return cchRet + cchSeg + fPendingSpace;
4883 }
4884 }
4885 }
4886 else
4887 KMK_CC_ASSERT(offWord == offEsc);
4888
4889 /* Next line. */
4890 offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq;
4891 iEscEol++;
4892
4893 /* Strip leading spaces. */
4894 while (offWord < offLineEnd && KMK_CC_EVAL_IS_SPACE(pszContent[offWord]))
4895 offWord++;
4896 if (offWord >= offLineEnd)
4897 {
4898 pCompiler->cStrCopySegs = cSegs;
4899 pCompiler->iEscEol = iEscEol;
4900 return cchRet;
4901 }
4902 } while (iEscEol < cEscEols);
4903
4904 /*
4905 * The last line.
4906 */
4907 cchSeg = offLineEnd - offWord;
4908 cchRet += cchSeg;
4909 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord];
4910 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace
4911 ? -(ssize_t)cchSeg : (ssize_t)cchSeg;
4912 pCompiler->cStrCopySegs = cSegs + 1;
4913 pCompiler->iEscEol = iEscEol;
4914 }
4915 }
4916 /*
4917 * Odd case: Nothing to copy.
4918 */
4919 else
4920 {
4921 cchRet = 0;
4922 pCompiler->cStrCopySegs = 0;
4923 }
4924 return cchRet;
4925}
4926
4927
4928/**
4929 * Prepares for copying a normal line, from the given position all the way to
4930 * the end.
4931 *
4932 * In addition to the returned information, this will store instruction in
4933 * paStrCopySegs and cSTrCopySeg for the following kmk_cc_eval_strcpyv() call.
4934 *
4935 * @returns The number of chars that will be copied by kmk_cc_eval_strcpyv().
4936 * @param pCompiler The compiler instance data.
4937 * @param pchWord Pointer to the first char to copy from the
4938 * current line. This must be the start of a
4939 * word.
4940 * @param cchLeft The number of chars left on the current line
4941 * starting at @a pchWord.
4942 */
4943static size_t kmk_cc_eval_prep_normal_line(PKMKCCEVALCOMPILER pCompiler, const char * const pchWord, size_t cchLeft)
4944{
4945 size_t cchRet;
4946 unsigned iEscEol = pCompiler->iEscEol;
4947 unsigned const cEscEols = pCompiler->cEscEols;
4948
4949 KMK_CC_ASSERT(cchLeft > 0);
4950 KMK_CC_ASSERT(!KMK_CC_EVAL_IS_SPACE(*pchWord)); /* The fact that we're standing at a word, is exploited below. */
4951 KMK_CC_ASSERT(iEscEol <= cEscEols);
4952
4953 /*
4954 * If there are no escaped EOLs left, just copy what was specified,
4955 * optionally sans any trailing spaces.
4956 */
4957 if (iEscEol >= cEscEols)
4958 {
4959 cchRet = cchLeft;
4960
4961 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, 1);
4962 pCompiler->cStrCopySegs = 1;
4963 pCompiler->paStrCopySegs[0].pchSrc = pchWord;
4964 pCompiler->paStrCopySegs[0].cchSrcAndPrependSpace = cchRet;
4965 }
4966 /*
4967 * Ok, we have to deal with escaped EOLs and do the proper
4968 * replacement of escaped newlines with space. The deal is that we
4969 * collaps all whitespace before and after one or more newlines into a
4970 * single space. (FreeBSD make does this differently, by the by.)
4971 */
4972 else
4973 {
4974 const char *pszContent = pCompiler->pszContent;
4975 size_t offWord = pchWord - pCompiler->pszContent;
4976 size_t offEsc;
4977 size_t fPendingSpace;
4978 size_t cchSeg;
4979 unsigned cSegs = 0;
4980
4981 /* Go nuts checking our preconditions here. */
4982 KMK_CC_ASSERT(offWord >= pCompiler->offLine);
4983 KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->offLine + pCompiler->cchLine);
4984 KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->cchContent);
4985 KMK_CC_ASSERT(offWord < pCompiler->paEscEols[iEscEol].offEsc);
4986 KMK_CC_ASSERT(offWord >= (iEscEol ? pCompiler->paEscEols[iEscEol - 1].offEol + pCompiler->cchEolSeq : pCompiler->offLine));
4987
4988 /* Make sure we've got more than enough segments to fill in. */
4989 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, cEscEols - iEscEol + 2);
4990
4991 /*
4992 * First line - We're at the start of a word, so no left stripping needed.
4993 */
4994 offEsc = pCompiler->paEscEols[iEscEol].offEsc;
4995 KMK_CC_ASSERT(offEsc > offWord);
4996 while (KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1]))
4997 offEsc--;
4998 KMK_CC_ASSERT(offEsc > offWord);
4999
5000 fPendingSpace = 1;
5001 cchRet = offEsc - offWord;
5002 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = cchRet;
5003 pCompiler->paStrCopySegs[cSegs].pchSrc = pchWord;
5004 cSegs++;
5005
5006 offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq;
5007 iEscEol++;
5008
5009 /*
5010 * All but the last line.
5011 */
5012 while (iEscEol < cEscEols)
5013 {
5014 offEsc = pCompiler->paEscEols[iEscEol].offEsc;
5015
5016 /* Strip leading spaces. */
5017 while (offWord < offEsc && KMK_CC_EVAL_IS_SPACE(pszContent[offWord]))
5018 offWord++;
5019
5020 if (offWord < offEsc)
5021 {
5022 /* Strip trailing spaces. */
5023 while (KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1]))
5024 offEsc--;
5025 cchSeg = offEsc - offWord;
5026 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace ? -(ssize_t)cchSeg : (ssize_t)cchSeg;
5027 cchRet += cchSeg + fPendingSpace;
5028 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord];
5029 cSegs += 1;
5030 fPendingSpace = 1;
5031 }
5032
5033 /* Next. */
5034 offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq;
5035 iEscEol++;
5036 }
5037
5038 /*
5039 * Final line. We must calculate the end of line offset our selves here.
5040 */
5041 offEsc = &pchWord[cchLeft] - pszContent;
5042 while (offWord < offEsc && KMK_CC_EVAL_IS_SPACE(pszContent[offWord]))
5043 offWord++;
5044
5045 if (offWord < offEsc)
5046 {
5047 cchSeg = offEsc - offWord;
5048 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace ? -(ssize_t)cchSeg : (ssize_t)cchSeg;
5049 cchRet += cchSeg + fPendingSpace;
5050 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord];
5051 cSegs += 1;
5052 }
5053
5054 pCompiler->cStrCopySegs = cSegs;
5055 }
5056 return cchRet;
5057}
5058
5059
5060/**
5061 * Common worker for all kmk_cc_eval_do_if*() functions.
5062 *
5063 * @param pCompiler The compiler state.
5064 * @param pIfCore The new IF statement.
5065 * @param fInElse Set if this is an 'else if' (rather than just 'if').
5066 */
5067static void kmk_cc_eval_do_if_core(PKMKCCEVALCOMPILER pCompiler, PKMKCCEVALIFCORE pIfCore, int fInElse)
5068{
5069 unsigned iIf = pCompiler->cIfs;
5070 if (!fInElse)
5071 {
5072 /* Push an IF statement. */
5073 if (iIf < KMK_CC_EVAL_MAX_IF_DEPTH)
5074 {
5075 pCompiler->cIfs = iIf + 1;
5076 pCompiler->apIfs[iIf] = pIfCore;
5077 pIfCore->pPrevCond = NULL;
5078 }
5079 else
5080 kmk_cc_eval_fatal(pCompiler, NULL, "Too deep IF nesting");
5081 }
5082 else if (iIf > 0)
5083 {
5084 /* Link an IF statement. */
5085 iIf--;
5086 pIfCore->pPrevCond = pCompiler->apIfs[iIf];
5087 pCompiler->apIfs[iIf] = pIfCore;
5088 }
5089 else
5090 kmk_cc_eval_fatal(pCompiler, NULL, "'else if' without 'if'");
5091 pIfCore->pNextTrue = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail);
5092 pIfCore->pNextFalse = NULL; /* This is set by else or endif. */
5093 pIfCore->pTrueEndJump = NULL; /* This is set by else or endif. */
5094}
5095
5096
5097/**
5098 * Deals with 'if expr' and 'else if expr' statements.
5099 *
5100 * @returns 1 to indicate we've handled a keyword (see
5101 * kmk_cc_eval_try_handle_keyword).
5102 * @param pCompiler The compiler state.
5103 * @param pchWord First char after 'if'.
5104 * @param cchLeft The number of chars left to parse on this line.
5105 * @param fInElse Set if this is an 'else if' (rather than just 'if').
5106 */
5107static int kmk_cc_eval_do_if(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse)
5108{
5109 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5110 if (cchLeft)
5111 {
5112 PKMKCCEVALIFEXPR pInstr;
5113 size_t cchExpr = kmk_cc_eval_prep_normal_line(pCompiler, pchWord, cchLeft);
5114 kmk_cc_eval_strip_right_v(pCompiler->paStrCopySegs, &pCompiler->cStrCopySegs, &cchExpr);
5115
5116 pInstr = (PKMKCCEVALIFEXPR)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, KMKCCEVALIFEXPR_SIZE(cchExpr));
5117 kmk_cc_eval_strcpyv(pInstr->szExpr, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, cchExpr);
5118 pInstr->cchExpr = cchExpr;
5119 pInstr->IfCore.Core.enmOpcode = kKmkCcEvalInstr_if;
5120 pInstr->IfCore.Core.iLine = pCompiler->iLine;
5121 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse);
5122 }
5123 else
5124 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive");
5125 return 1;
5126}
5127
5128
5129/**
5130 * Deals with 'ifdef var', 'ifndef var', 'else ifdef var' and 'else ifndef var'
5131 * statements.
5132 *
5133 * @returns 1 to indicate we've handled a keyword (see
5134 * kmk_cc_eval_try_handle_keyword).
5135 * @param pCompiler The compiler state.
5136 * @param pchWord First char after 'if[n]def'.
5137 * @param cchLeft The number of chars left to parse on this line.
5138 * @param fInElse Set if this is an 'else if' (rather than just 'if').
5139 * @param fPositiveStmt Set if 'ifdef', clear if 'ifndef'.
5140 */
5141static int kmk_cc_eval_do_ifdef(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt)
5142{
5143 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5144 if (cchLeft)
5145 {
5146 /*
5147 * Skip to the end of the variable name.
5148 */
5149 unsigned const iSavedEscEol = pCompiler->iEscEol;
5150 const char * const pchVarNm = pchWord;
5151 int fPlain;
5152/** @todo this isn't quite right. It is a variable name, correct. However, it
5153 * doesn't need to subscribe entirely to the rules of a variable name.
5154 * Just find the end of the word, taking variable refs into account,
5155 * and consider it what we need. */
5156 pchWord = kmk_cc_eval_skip_var_name(pCompiler, pchWord, cchLeft, &cchLeft, &fPlain);
5157 KMK_CC_ASSERT(pCompiler->iEscEol == iSavedEscEol || !fPlain);
5158 if (fPlain)
5159 {
5160 size_t const cchVarNm = pchWord - pchVarNm;
5161 PKMKCCEVALIFDEFPLAIN pInstr;
5162 pInstr = (PKMKCCEVALIFDEFPLAIN)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
5163 pInstr->IfCore.Core.enmOpcode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_plain : kKmkCcEvalInstr_ifndef_plain;
5164 pInstr->IfCore.Core.iLine = pCompiler->iLine;
5165 pInstr->pszName = strcache2_add(&variable_strcache, pchVarNm, cchVarNm);
5166 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse);
5167 }
5168 else
5169 {
5170 PKMKCCEVALIFDEFDYNAMIC pInstr;
5171 size_t const cchVarNm = pchWord - pchVarNm;
5172 size_t cchCopy;
5173 char *pszCopy;
5174 pCompiler->iEscEol = iSavedEscEol;
5175 cchCopy = kmk_cc_eval_prep_normal_line(pCompiler, pchVarNm, cchVarNm);
5176
5177 pInstr = (PKMKCCEVALIFDEFDYNAMIC)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
5178
5179 /** @todo Make the subprogram embed necessary strings. */
5180 pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, cchCopy);
5181 kmk_cc_block_realign(pCompiler->ppBlockTail);
5182
5183 pInstr->IfCore.Core.enmOpcode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_dynamic : kKmkCcEvalInstr_ifndef_dynamic;
5184 pInstr->IfCore.Core.iLine = pCompiler->iLine;
5185 pInstr->uPadding = 0;
5186 kmk_cc_eval_compile_string_exp_subprog(pCompiler, pszCopy, cchCopy, &pInstr->NameSubprog);
5187
5188 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse);
5189 }
5190
5191 /*
5192 * Make sure there is nothing following the variable name.
5193 */
5194 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5195 if (cchLeft)
5196 kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'if%sdef' variable name", fPositiveStmt ? "" : "n");
5197 }
5198 else
5199 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive");
5200 return 1;
5201}
5202
5203
5204/**
5205 * Deals with 'ifeq (a,b)', 'ifeq "a" "b"', 'ifneq (a,b)', 'ifneq "a" "b"',
5206 * 'else ifeq (a,b)', 'else ifeq "a" "b"', 'else ifneq (a,b)' and
5207 * 'else ifneq "a" "b"' statements.
5208 *
5209 * @returns 1 to indicate we've handled a keyword (see
5210 * kmk_cc_eval_try_handle_keyword).
5211 * @param pCompiler The compiler state.
5212 * @param pchWord First char after 'if[n]eq'.
5213 * @param cchLeft The number of chars left to parse on this line.
5214 * @param fInElse Set if this is an 'else if' (rather than just 'if').
5215 * @param fPositiveStmt Set if 'ifeq', clear if 'ifneq'.
5216 */
5217static int kmk_cc_eval_do_ifeq(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt)
5218{
5219 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5220 if (cchLeft)
5221 {
5222 /*
5223 * There are two forms:
5224 *
5225 * ifeq (string1, string2)
5226 * ifeq "string1" 'string2'
5227 *
5228 */
5229 const char * const pchEnd = &pchWord[cchLeft];
5230 PKMKCCEVALIFEQ pInstr = (PKMKCCEVALIFEQ)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
5231
5232 struct
5233 {
5234 char *pszCopy;
5235 size_t cchCopy;
5236 int fPlain;
5237 } Left, Right;
5238
5239 char ch = *pchWord;
5240 if (ch == '(')
5241 {
5242 int cCounts;
5243 size_t off;
5244
5245 /*
5246 * The left side ends with a comma. We respect parentheses, but
5247 * not curly brackets.
5248 */
5249
5250 /* Skip the parenthesis. */
5251 pchWord++;
5252 cchLeft--;
5253
5254 /* Find the comma, checking for non-plainness. */
5255 cCounts = 0;
5256 Left.fPlain = 1;
5257 for (off = 0; off < cchLeft; off++)
5258 {
5259 ch = pchWord[off];
5260 if (!KMK_CC_EVAL_IS_PAREN_COMMA_OR_DOLLAR(ch))
5261 { /* likely */ }
5262 else if (ch == '$')
5263 Left.fPlain = 0;
5264 else if (ch == '(')
5265 cCounts++;
5266 else if (ch == ')')
5267 cCounts--; /** @todo warn if it goes negative. */
5268 else if (ch == ',' && cCounts == 0)
5269 break;
5270 else
5271 KMK_CC_ASSERT(cCounts > 0);
5272 }
5273 if (ch == ',' && cCounts == 0) { /* likely */ }
5274 else kmk_cc_eval_fatal(pCompiler, &pchWord[off], "Expected ',' before end of line");
5275
5276 /* Copy out the string. */
5277 Left.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, off);
5278 kmk_cc_eval_strip_right_v(pCompiler->paStrCopySegs, &pCompiler->cStrCopySegs, &Left.cchCopy);
5279 Left.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Left.cchCopy);
5280
5281 /* Skip past the comma and any following spaces. */
5282 pchWord += off + 1;
5283 cchLeft -= off + 1;
5284 if ( cchLeft /** @todo replace with straight 'isspace' that takes escaped EOLs into account. */
5285 && KMK_CC_EVAL_IS_SPACE_AFTER_WORD(pCompiler, pchWord[0], pchWord[1], cchLeft))
5286 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5287
5288 /*
5289 * Ditto for the right side, only it ends with a closing parenthesis.
5290 */
5291 cCounts = 1;
5292 Right.fPlain = 1;
5293 for (off = 0; off < cchLeft; off++)
5294 {
5295 ch = pchWord[off];
5296 if (!KMK_CC_EVAL_IS_PAREN_COMMA_OR_DOLLAR(ch))
5297 { /* likely */ }
5298 else if (ch == '$')
5299 Right.fPlain = 0;
5300 else if (ch == '(')
5301 cCounts++;
5302 else if (ch == ')')
5303 {
5304 if (--cCounts == 0)
5305 break;
5306 }
5307 else
5308 KMK_CC_ASSERT(cCounts > 0 || ch == ',');
5309 }
5310 if (ch == ')' && cCounts == 0) { /* likely */ }
5311 else kmk_cc_eval_fatal(pCompiler, &pchWord[off], "Expected ')' before end of line");
5312
5313 /* Copy out the string. */
5314 Right.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, off);
5315 kmk_cc_eval_strip_right_v(pCompiler->paStrCopySegs, &pCompiler->cStrCopySegs, &Right.cchCopy);
5316 Right.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Right.cchCopy);
5317
5318 /* Skip past the parenthesis. */
5319 pchWord += off + 1;
5320 cchLeft -= off + 1;
5321 }
5322 else if (ch == '"' || ch == '\'')
5323 {
5324 const char *pchTmp;
5325
5326 /*
5327 * Quoted left side.
5328 */
5329 /* Skip leading quote. */
5330 pchWord++;
5331 cchLeft--;
5332
5333 /* Locate the end quote. */
5334 pchTmp = (const char *)memchr(pchWord, ch, cchLeft);
5335 if (pchTmp) { /* likely */ }
5336 else kmk_cc_eval_fatal(pCompiler, pchWord - 1, "Unbalanced quote in first if%seq string", fPositiveStmt ? "" : "n");
5337
5338 Left.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, pchTmp - pchWord);
5339 Left.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Left.cchCopy);
5340 Left.fPlain = memchr(Left.pszCopy, '$', Left.cchCopy) == NULL;
5341
5342 /* skip end quote */
5343 pchWord = pchTmp + 1;
5344 cchLeft = pchEnd - pchWord;
5345
5346 /* Skip anything inbetween the left and right hand side (not mandatory). */
5347 if ( cchLeft /** @todo replace with straight 'isspace' that takes escaped EOLs into account. */
5348 && KMK_CC_EVAL_IS_SPACE_AFTER_WORD(pCompiler, pchWord[0], pchWord[1], cchLeft))
5349 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5350
5351 /*
5352 * Quoted right side.
5353 */
5354 if ( cchLeft > 0
5355 && ( (ch = *pchWord) != '"' || ch == '\'') )
5356 {
5357 /* Skip leading quote. */
5358 pchWord++;
5359 cchLeft--;
5360
5361 /* Locate the end quote. */
5362 pchTmp = (const char *)memchr(pchWord, ch, cchLeft);
5363 if (pchTmp) { /* likely */ }
5364 else kmk_cc_eval_fatal(pCompiler, pchWord - 1, "Unbalanced quote in second if%seq string", fPositiveStmt ? "" : "n");
5365
5366 Right.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, pchTmp - pchWord);
5367 Right.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Right.cchCopy);
5368 Right.fPlain = memchr(Right.pszCopy, '$', Right.cchCopy) == NULL;
5369
5370 /* skip end quote */
5371 pchWord = pchTmp + 1;
5372 cchLeft = pchEnd - pchWord;
5373 }
5374 else
5375 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected a second quoted string for 'if%seq'",
5376 fPositiveStmt ? "" : "n");
5377 }
5378 else
5379 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected parentheses or quoted string after 'if%seq'",
5380 fPositiveStmt ? "" : "n");
5381 kmk_cc_block_realign(pCompiler->ppBlockTail);
5382
5383 /*
5384 * Initialize the instruction.
5385 */
5386 pInstr->IfCore.Core.enmOpcode = fPositiveStmt ? kKmkCcEvalInstr_ifeq : kKmkCcEvalInstr_ifneq;
5387 pInstr->IfCore.Core.iLine = pCompiler->iLine;
5388 kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Left, Left.pszCopy, Left.cchCopy, Left.fPlain);
5389 kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Right, Right.pszCopy, Right.cchCopy, Right.fPlain);
5390 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse);
5391
5392 /*
5393 * Make sure there is nothing following the variable name.
5394 */
5395 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5396 if (cchLeft)
5397 kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'if%sdef' variable name", fPositiveStmt ? "" : "n");
5398 }
5399 else
5400 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive");
5401 return 1;
5402}
5403
5404
5405/**
5406 * Deals with 'if1of (set-a,set-b)', 'ifn1of (set-a,set-b)',
5407 * 'else if1of (set-a,set-b)' and 'else ifn1of (set-a,set-b)' statements.
5408 *
5409 * @returns 1 to indicate we've handled a keyword (see
5410 * kmk_cc_eval_try_handle_keyword).
5411 * @param pCompiler The compiler state.
5412 * @param pchWord First char after 'if[n]1of'.
5413 * @param cchLeft The number of chars left to parse on this line.
5414 * @param fInElse Set if this is an 'else if' (rather than just 'if').
5415 * @param fPositiveStmt Set if 'if1of', clear if 'ifn1of'.
5416 */
5417static int kmk_cc_eval_do_if1of(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt)
5418{
5419 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5420 if (cchLeft)
5421 {
5422 /*
5423 * This code is (currently) very similar to kmk_cc_eval_do_ifeq.
5424 * However, we may want to add hashing optimizations of plain text,
5425 * and we don't want to support the quoted form as it is not necessary
5426 * and may interfere with support for quoted words later on.
5427 */
5428 PKMKCCEVALIF1OF pInstr = (PKMKCCEVALIF1OF)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
5429
5430 struct
5431 {
5432 char *pszCopy;
5433 size_t cchCopy;
5434 int fPlain;
5435 } Left, Right;
5436
5437 char ch = *pchWord;
5438 if (ch == '(')
5439 {
5440 int cCounts;
5441 size_t off;
5442
5443 /*
5444 * The left side ends with a comma. We respect parentheses, but
5445 * not curly brackets.
5446 */
5447
5448 /* Skip the parenthesis. */
5449 pchWord++;
5450 cchLeft--;
5451
5452 /* Find the comma, checking for non-plainness. */
5453 cCounts = 0;
5454 Left.fPlain = 1;
5455 for (off = 0; off < cchLeft; off++)
5456 {
5457 ch = pchWord[off];
5458 if (!KMK_CC_EVAL_IS_PAREN_COMMA_OR_DOLLAR(ch))
5459 { /* likely */ }
5460 else if (ch == '$')
5461 Left.fPlain = 0;
5462 else if (ch == '(')
5463 cCounts++;
5464 else if (ch == ')')
5465 cCounts--; /** @todo warn if it goes negative. */
5466 else if (ch == ',' && cCounts == 0)
5467 break;
5468 else
5469 KMK_CC_ASSERT(cCounts > 0);
5470 }
5471 if (ch == ',' && cCounts == 0) { /* likely */ }
5472 else kmk_cc_eval_fatal(pCompiler, &pchWord[off], "Expected ',' before end of line");
5473
5474 /* Copy out the string. */
5475 Left.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, off);
5476 kmk_cc_eval_strip_right_v(pCompiler->paStrCopySegs, &pCompiler->cStrCopySegs, &Left.cchCopy);
5477 Left.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Left.cchCopy);
5478
5479 /* Skip past the comma and any following spaces. */
5480 pchWord += off + 1;
5481 cchLeft -= off + 1;
5482 if ( cchLeft /** @todo replace with straight 'isspace' that takes escaped EOLs into account. */
5483 && KMK_CC_EVAL_IS_SPACE_AFTER_WORD(pCompiler, pchWord[0], pchWord[1], cchLeft))
5484 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5485
5486 /*
5487 * Ditto for the right side, only it ends with a closing parenthesis.
5488 */
5489 cCounts = 1;
5490 Right.fPlain = 1;
5491 for (off = 0; off < cchLeft; off++)
5492 {
5493 ch = pchWord[off];
5494 if (!KMK_CC_EVAL_IS_PAREN_COMMA_OR_DOLLAR(ch))
5495 { /* likely */ }
5496 else if (ch == '$')
5497 Right.fPlain = 0;
5498 else if (ch == '(')
5499 cCounts++;
5500 else if (ch == ')')
5501 {
5502 if (--cCounts == 0)
5503 break;
5504 }
5505 else
5506 KMK_CC_ASSERT(cCounts > 0 || ch == ',');
5507 }
5508 if (ch == ')' && cCounts == 0) { /* likely */ }
5509 else kmk_cc_eval_fatal(pCompiler, &pchWord[off], "Expected ')' before end of line");
5510
5511 /* Copy out the string. */
5512 Right.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, off);
5513 kmk_cc_eval_strip_right_v(pCompiler->paStrCopySegs, &pCompiler->cStrCopySegs, &Right.cchCopy);
5514 Right.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Right.cchCopy);
5515
5516 /* Skip past the parenthesis. */
5517 pchWord += off + 1;
5518 cchLeft -= off + 1;
5519 }
5520 else
5521 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected parentheses after 'if%s1of'", fPositiveStmt ? "" : "n");
5522 kmk_cc_block_realign(pCompiler->ppBlockTail);
5523
5524 /*
5525 * Initialize the instruction.
5526 */
5527 pInstr->IfCore.Core.enmOpcode = fPositiveStmt ? kKmkCcEvalInstr_if1of : kKmkCcEvalInstr_ifn1of;
5528 pInstr->IfCore.Core.iLine = pCompiler->iLine;
5529 kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Left, Left.pszCopy, Left.cchCopy, Left.fPlain);
5530 kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Right, Right.pszCopy, Right.cchCopy, Right.fPlain);
5531 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse);
5532
5533 /*
5534 * Make sure there is nothing following the variable name.
5535 */
5536 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5537 if (cchLeft)
5538 kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'if%s1of' variable name", fPositiveStmt ? "" : "n");
5539 }
5540 else
5541 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive");
5542 return 1;
5543}
5544
5545
5546/**
5547 * Deals with 'else' and 'else ifxxx' statements.
5548 *
5549 * @returns 1 to indicate we've handled a keyword (see
5550 * kmk_cc_eval_try_handle_keyword).
5551 * @param pCompiler The compiler state.
5552 * @param pchWord First char after 'define'.
5553 * @param cchLeft The number of chars left to parse on this line.
5554 */
5555static int kmk_cc_eval_do_else(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
5556{
5557 /*
5558 * There must be an 'if' on the stack.
5559 */
5560 unsigned iIf = pCompiler->cIfs;
5561 if (iIf > 0)
5562 {
5563 PKMKCCEVALIFCORE pIfCore = pCompiler->apIfs[--iIf];
5564 if (!pIfCore->pTrueEndJump)
5565 {
5566 /* Emit a jump instruction that will take us from the 'True' block to the 'endif'. */
5567 PKMKCCEVALJUMP pInstr = (PKMKCCEVALJUMP)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
5568 pInstr->Core.enmOpcode = kKmkCcEvalInstr_jump;
5569 pInstr->Core.iLine = pCompiler->iLine;
5570 pInstr->pNext = NULL;
5571 pIfCore->pTrueEndJump = pInstr;
5572
5573 /* The next instruction is the first in the 'False' block of the current 'if'.
5574 Should this be an 'else if', this will be the 'if' instruction emitted below. */
5575 pIfCore->pNextFalse = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail);
5576 }
5577 else if (iIf == 0)
5578 kmk_cc_eval_fatal(pCompiler, pchWord, "2nd 'else' for 'if' at line %u", pIfCore->Core.iLine);
5579 else
5580 kmk_cc_eval_fatal(pCompiler, pchWord, "2nd 'else' in a row - missing 'endif' for 'if' at line %u?",
5581 pIfCore->Core.iLine);
5582 }
5583 else
5584 kmk_cc_eval_fatal(pCompiler, pchWord, "'else' without 'if'");
5585
5586 /*
5587 * Check for 'else ifxxx'. There can be nothing else following an else.
5588 */
5589 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5590 if (cchLeft)
5591 {
5592 if ( cchLeft > 2
5593 && KMK_CC_WORD_COMP_CONST_2(pchWord, "if"))
5594 {
5595 pchWord += 2;
5596 cchLeft -= 2;
5597
5598 if (KMK_CC_EVAL_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
5599 return kmk_cc_eval_do_if(pCompiler, pchWord, cchLeft, 1 /* in else */);
5600
5601 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "eq", 2))
5602 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 2, cchLeft - 2, 1 /* in else */, 1 /* positive */);
5603
5604 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "def", 3))
5605 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 1 /* positive */);
5606
5607 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "neq", 3))
5608 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 0 /* positive */);
5609
5610 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "1of", 3))
5611 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 1 /* positive */);
5612
5613 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "ndef", 4))
5614 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 4, cchLeft - 4, 1 /* in else */, 0 /* positive */);
5615
5616 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "n1of", 4))
5617 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 4, cchLeft - 4, 1 /* in else */, 0 /* positive */);
5618
5619 pchWord -= 2;
5620 cchLeft += 2;
5621 }
5622 kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'else'");
5623 }
5624
5625 return 1;
5626}
5627
5628
5629/**
5630 * Deals with the 'endif' statement.
5631 *
5632 * @returns 1 to indicate we've handled a keyword (see
5633 * kmk_cc_eval_try_handle_keyword).
5634 * @param pCompiler The compiler state.
5635 * @param pchWord First char after 'define'.
5636 * @param cchLeft The number of chars left to parse on this line.
5637 */
5638static int kmk_cc_eval_do_endif(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
5639{
5640 /*
5641 * There must be an 'if' on the stack. We'll POP it.
5642 */
5643 unsigned iIf = pCompiler->cIfs;
5644 if (iIf > 0)
5645 {
5646 PKMKCCEVALCORE pNextInstr;
5647 PKMKCCEVALIFCORE pIfCore = pCompiler->apIfs[--iIf];
5648 pCompiler->cIfs = iIf; /* POP! */
5649
5650 /* Update the jump targets for all IFs at this level. */
5651 pNextInstr = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail);
5652 do
5653 {
5654 if (pIfCore->pTrueEndJump)
5655 {
5656 /* Make the true block jump here, to the 'endif'. The false block is already here. */
5657 pIfCore->pTrueEndJump->pNext = pNextInstr;
5658 KMK_CC_ASSERT(pIfCore->pNextFalse);
5659 }
5660 else
5661 {
5662 /* No 'else'. The false-case jump here, to the 'endif'. */
5663 KMK_CC_ASSERT(!pIfCore->pNextFalse);
5664 pIfCore->pNextFalse = pNextInstr;
5665 }
5666
5667 pIfCore = pIfCore->pPrevCond;
5668 } while (pIfCore);
5669 }
5670 else
5671 kmk_cc_eval_fatal(pCompiler, pchWord, "'endif' without 'if'");
5672
5673 /*
5674 * There shouldn't be anything trailing an 'endif'.
5675 */
5676 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5677 if (!cchLeft) { /* likely */ }
5678 else kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'else'");
5679
5680 return 1;
5681}
5682
5683
5684/**
5685 * Parses a 'include file...', 'sinclude file...', '-include file...',
5686 * 'includedep file...', 'includedep-queue file...' and
5687 * 'includedep-flush file...'
5688 *
5689 * @returns 1 to indicate we've handled a keyword (see
5690 * kmk_cc_eval_try_handle_keyword).
5691 * @param pCompiler The compiler state.
5692 * @param pchWord First char after the include directive.
5693 * @param cchLeft The number of chars left to parse on this line.
5694 * @param enmOpcode The opcode for the include directive we're parsing.
5695 */
5696static int kmk_cc_eval_do_include(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, KMKCCEVALINSTR enmOpcode)
5697{
5698 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5699 if (cchLeft)
5700 {
5701 /*
5702 * Split what's left up into words.
5703 */
5704 unsigned cWords = kmk_cc_eval_parse_words(pCompiler, pchWord, cchLeft);
5705 KMK_CC_EVAL_DPRINTF(("%s: cWords=%d\n", g_apszEvalInstrNms[enmOpcode], cWords));
5706 if (cWords)
5707 {
5708 PKMKCCEVALINCLUDE pInstr = (PKMKCCEVALINCLUDE)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail,
5709 KMKCCEVALINCLUDE_SIZE(cWords));
5710 pInstr->Core.enmOpcode = enmOpcode;
5711 pInstr->Core.iLine = pCompiler->iLine;
5712 pInstr->cFiles = cWords;
5713 kmk_cc_eval_init_spp_array_from_duplicated_words(pCompiler, cWords, pCompiler->paWords, pInstr->aFiles);
5714 kmk_cc_block_realign(pCompiler->ppBlockTail);
5715 }
5716 else
5717 KMK_CC_ASSERT(0);
5718 }
5719 else
5720 KMK_CC_EVAL_DPRINTF(("%s: include without args\n", g_apszEvalInstrNms[enmOpcode]));
5721 return 1;
5722}
5723
5724
5725static int kmk_cc_eval_do_vpath(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
5726{
5727 kmk_cc_eval_fatal(pCompiler, NULL, "vpath directive is not implemented\n");
5728 return 1;
5729}
5730
5731
5732/**
5733 * Called when any previous recipe must have ended and can be finalized.
5734 *
5735 * This occurs when encountering an assignement, a new recipe or the end of the
5736 * complication unit.
5737 *
5738 * @param pCompiler The compiler state.
5739 */
5740static void kmk_cc_eval_end_of_recipe(PKMKCCEVALCOMPILER pCompiler, const char *pchWord)
5741{
5742 if (pCompiler->pRecipe)
5743 {
5744 /** @todo do stuff here. */
5745 kmk_cc_eval_fatal(pCompiler, pchWord, "end-of-recipe handling not implemented yet");
5746 }
5747}
5748
5749
5750static void kmk_cc_eval_handle_command(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
5751{
5752 kmk_cc_eval_fatal(pCompiler, pchWord, "command handling not implemented yet");
5753}
5754
5755
5756/**
5757 * Pick up the recipe parsing at the colon.
5758 *
5759 * @returns 1 to indicate we've handled a keyword (see
5760 * kmk_cc_eval_try_handle_keyword).
5761 * @param pCompiler The compiler state.
5762 * @param pchWord0 The first word.
5763 * @param cchWord0 The length of the first word.
5764 * @param enmToken0 The classification of the first word.
5765 * @param pchColon The colon.
5766 * @param cchLeft How much is left, starting at the colon.
5767 */
5768static int kmk_cc_eval_handle_recipe_cont_colon(PKMKCCEVALCOMPILER pCompiler, const char *pchWord0, size_t cchWord0,
5769 KMKCCEVALTOKEN enmToken0, const char *pchColon, size_t cchLeft)
5770{
5771 kmk_cc_eval_fatal(pCompiler, pchWord0, "recipe handling not implemented yet (#1)");
5772 return 1;
5773}
5774
5775
5776/**
5777 * Pick up the recipe parsing at the 2nd word (after it was determined not to be
5778 * an assignment operator after all).
5779 *
5780 * @returns 1 to indicate we've handled a keyword (see
5781 * kmk_cc_eval_try_handle_keyword).
5782 * @param pCompiler The compiler state.
5783 * @param pchWord0 The first word.
5784 * @param cchWord0 The length of the first word.
5785 * @param pchWord Where to continue parsing.
5786 * @param cchLeft How much is left to parse.
5787 */
5788static int kmk_cc_eval_handle_recipe_cont_2nd_word(PKMKCCEVALCOMPILER pCompiler, const char *pchWord0, size_t cchWord0,
5789 const char *pchWord, size_t cchLeft)
5790{
5791// const char *pchColon = memchr()
5792
5793 kmk_cc_eval_fatal(pCompiler, pchWord, "recipe handling not implemented yet (#2)");
5794 return 1;
5795}
5796
5797
5798static void kmk_cc_eval_handle_recipe(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
5799{
5800 const char *pszColon = NULL;//memchr(pchWord, cchLeft);
5801 if (pszColon)
5802 {
5803
5804
5805 kmk_cc_eval_fatal(pCompiler, pchWord, "recipe handling not implemented yet (#3)");
5806 }
5807 else if (pchWord[0] == '$')
5808 {
5809
5810 }
5811 else
5812 kmk_cc_eval_fatal(pCompiler, pchWord,
5813 "Not variable assignment. Could be a complicated indirect recipe definition, however that's currently not supported.");
5814
5815}
5816
5817
5818
5819/**
5820 * Common worker for handling export (non-assign), undefine and unexport.
5821 *
5822 * For instructions using the KMKCCEVALVARIABLES structure.
5823 *
5824 * @returns 1 to indicate we've handled a keyword (see
5825 * kmk_cc_eval_try_handle_keyword).
5826 * @param pCompiler The compiler state.
5827 * @param pchWord First non-space chare after the keyword.
5828 * @param cchLeft The number of chars left to parse on this line.
5829 * @param fQualifiers The qualifiers.
5830 */
5831static int kmk_cc_eval_do_with_variable_list(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft,
5832 KMKCCEVALINSTR enmOpcode, unsigned fQualifiers)
5833{
5834 if (cchLeft)
5835 {
5836 /*
5837 * Parse the variable name list. GNU make is using normal word
5838 * handling here, so we can share code with the include directives.
5839 */
5840 unsigned cWords = kmk_cc_eval_parse_words(pCompiler, pchWord, cchLeft);
5841#ifdef KMK_CC_EVAL_LOGGING_ENABLED
5842 unsigned iWord;
5843 KMK_CC_EVAL_DPRINTF(("%s: cWords=%d\n", g_apszEvalInstrNms[enmOpcode], cWords));
5844 for (iWord = 0; iWord < cWords; iWord++)
5845 KMK_CC_EVAL_DPRINTF((" word[%u]: len=%#05x t=%d '%*.*s'\n", iWord, (int)pCompiler->paWords[iWord].cchWord,
5846 (int)pCompiler->paWords[iWord].enmToken, (int)pCompiler->paWords[iWord].cchWord,
5847 (int)pCompiler->paWords[iWord].cchWord, pCompiler->paWords[iWord].pchWord));
5848#endif
5849 if (cWords)
5850 {
5851 PKMKCCEVALVARIABLES pInstr = (PKMKCCEVALVARIABLES)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail,
5852 KMKCCEVALVARIABLES_SIZE(cWords));
5853 pInstr->Core.enmOpcode = enmOpcode;
5854 pInstr->Core.iLine = pCompiler->iLine;
5855 pInstr->cVars = cWords;
5856 kmk_cc_eval_init_spp_array_from_duplicated_words(pCompiler, cWords, pCompiler->paWords, pInstr->aVars);
5857 kmk_cc_block_realign(pCompiler->ppBlockTail);
5858 }
5859 else
5860 KMK_CC_ASSERT(0);
5861 }
5862 /* else: NOP */
5863 return 1;
5864}
5865
5866
5867/**
5868 * Parses a '[qualifiers] undefine variable [..]' expression.
5869 *
5870 * A 'undefine' directive is final, any qualifiers must preceed it. So, we just
5871 * have to extract the variable names now.
5872 *
5873 * @returns 1 to indicate we've handled a keyword (see
5874 * kmk_cc_eval_try_handle_keyword).
5875 * @param pCompiler The compiler state.
5876 * @param pchWord First char after 'define'.
5877 * @param cchLeft The number of chars left to parse on this line.
5878 * @param fQualifiers The qualifiers.
5879 */
5880static int kmk_cc_eval_do_var_undefine(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers)
5881{
5882 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5883 if (!cchLeft)
5884 kmk_cc_eval_fatal(pCompiler, pchWord, "undefine requires a variable name");
5885
5886 /** @todo GNU make doesn't actually do the list thing for undefine, it seems
5887 * to assume everything after it is a single variable... Going with
5888 * simple common code for now. */
5889 return kmk_cc_eval_do_with_variable_list(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_undefine, fQualifiers);
5890}
5891
5892
5893/**
5894 * Parses a '[qualifiers] unexport variable [..]' expression.
5895 *
5896 * A 'unexport' directive is final, any qualifiers must preceed it. So, we just
5897 * have to extract the variable names now.
5898 *
5899 * @returns 1 to indicate we've handled a keyword (see
5900 * kmk_cc_eval_try_handle_keyword).
5901 * @param pCompiler The compiler state.
5902 * @param pchWord First char after 'define'.
5903 * @param cchLeft The number of chars left to parse on this line.
5904 * @param fQualifiers The qualifiers.
5905 */
5906static int kmk_cc_eval_do_var_unexport(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers)
5907{
5908 PKMKCCEVALCORE pInstr;
5909
5910 /*
5911 * Join paths with undefine and export, unless it's an unexport all directive.
5912 */
5913 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5914 if (cchLeft)
5915 return kmk_cc_eval_do_with_variable_list(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_unexport, fQualifiers);
5916
5917 /*
5918 * We're unexporting all variables.
5919 */
5920 pInstr = kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
5921 pInstr->enmOpcode = kKmkCcEvalInstr_unexport_all;
5922 pInstr->iLine = pCompiler->iLine;
5923 return 1;
5924}
5925
5926
5927/**
5928 * Parses a 'define variable' expression.
5929 *
5930 * A 'define' directive is final, any qualifiers must preceed it. So, we just
5931 * have to extract the variable name now, well and find the corresponding
5932 * 'endef'.
5933 *
5934 * @returns 1 to indicate we've handled a keyword (see
5935 * kmk_cc_eval_try_handle_keyword).
5936 * @param pCompiler The compiler state.
5937 * @param pchWord First char after 'define'.
5938 * @param cchLeft The number of chars left to parse on this line.
5939 * @param fQualifiers The qualifiers.
5940 */
5941static int kmk_cc_eval_do_var_define(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers)
5942{
5943 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5944 kmk_cc_eval_fatal(pCompiler, pchWord, "define handling not implemented yet");
5945 return 1;
5946}
5947
5948
5949/**
5950 * Emits a 'expand(-and-eval)' instruction.
5951 *
5952 * @returns 1 to indicate we've handled a keyword (see
5953 * kmk_cc_eval_try_handle_keyword).
5954 * @param pCompiler The compiler state.
5955 * @param pchSubprog The subprogram that needs expanding.
5956 * @param cchSubprog The length of the subprogram.
5957 * @param iEscEol The escaped EOL index corresponding to pchSubprog.
5958 */
5959static int kmk_cc_eval_emit_expand(PKMKCCEVALCOMPILER pCompiler, const char *pchSubprog, size_t cchSubprog, unsigned iEscEolVarNm)
5960{
5961 /*
5962 * We're unexporting all variables.
5963 */
5964 size_t cchCopy;
5965 char *pszCopy;
5966 PKMKCCEVALEXPAND pInstr;
5967
5968 pCompiler->iEscEol = iEscEolVarNm;
5969 cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchSubprog, cchSubprog);
5970 pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, cchCopy);
5971 kmk_cc_block_realign(pCompiler->ppBlockTail);
5972
5973 pInstr = (PKMKCCEVALEXPAND)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
5974 pInstr->Core.enmOpcode = kKmkCcEvalInstr_expand;
5975 pInstr->Core.iLine = pCompiler->iLine;
5976 pInstr->uPadding = 0;
5977 /** @todo Make the subprogram embed necessary strings. */
5978 kmk_cc_eval_compile_string_exp_subprog(pCompiler, pszCopy, cchCopy, &pInstr->Subprog);
5979
5980 return 1;
5981}
5982
5983
5984static int kmk_cc_eval_handle_assignment_or_recipe(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft,
5985 unsigned fQualifiers)
5986{
5987 /*
5988 * We're currently at a word which may or may not be a variable name
5989 * followed by an assignment operator, alternatively it must be a recipe.
5990 * We need to figure this out and deal with it in the most efficient
5991 * manner as this is a very common occurence.
5992 */
5993 unsigned const iEscEolVarNm = pCompiler->iEscEol;
5994 int fPlainVarNm = 1;
5995 const char *pchVarNm = pchWord;
5996 size_t cchVarNm;
5997 size_t cch = 0;
5998 size_t cchSubprog = 0;
5999 char ch;
6000
6001 /*
6002 * The variable name. Complicate by there being no requirement of a space
6003 * preceeding the assignment operator, as well as that the variable name
6004 * may include variable references with spaces (function++) in them.
6005 */
6006 for (;;)
6007 {
6008 if (cch < cchLeft)
6009 { /*likely*/ }
6010 else
6011 {
6012 /* Single word, join paths with word + whitespace. */
6013 KMK_CC_ASSERT(cch == cchLeft);
6014 cchVarNm = cch;
6015 pchWord += cch;
6016 cchLeft -= cch;
6017 break;
6018 }
6019
6020 ch = pchWord[cch];
6021 if (!KMK_CC_EVAL_IS_SPACE_DOLLAR_SLASH_OR_ASSIGN(ch))
6022 cch++;
6023 /* Space? */
6024 else if (KMK_CC_EVAL_IS_SPACE(ch))
6025 {
6026 cchVarNm = cch;
6027 pchWord += cch;
6028 cchLeft -= cch;
6029 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
6030 break;
6031 }
6032 /* Variable expansion may contain spaces, so handle specially. */
6033 else if (ch == '$')
6034 {
6035 size_t const offStart = cch;
6036 cch++;
6037 if (cch < cchLeft)
6038 {
6039 char const chOpen = pchWord[cch];
6040 if (chOpen == '(' || chOpen == '{')
6041 {
6042 /*
6043 * Got a $(VAR) or ${VAR} to deal with here. This may
6044 * include nested variable references and span multiple
6045 * lines (at least for function calls).
6046 *
6047 * We scan forward till we've found the corresponding
6048 * closing parenthesis, considering any open parentheses
6049 * of the same kind as worth counting, even if there are
6050 * no dollar preceeding them, just like GNU make does.
6051 */
6052 size_t const cchStart = cch - 1;
6053 char const chClose = chOpen == '(' ? ')' : '}';
6054 unsigned cOpen = 1;
6055 cch++;
6056 for (;;)
6057 {
6058 if (cch < cchLeft)
6059 {
6060 ch = pchWord[cch];
6061 if (!(KMK_CC_EVAL_IS_PAREN_OR_SLASH(ch)))
6062 cch++;
6063 else
6064 {
6065 cch++;
6066 if (ch == chClose)
6067 {
6068 if (--cOpen == 0)
6069 break;
6070 }
6071 else if (ch == chOpen)
6072 cOpen++;
6073 else if ( ch == '\\'
6074 && pCompiler->iEscEol < pCompiler->cEscEols
6075 && (size_t)(&pchWord[cch] - pCompiler->pszContent)
6076 == pCompiler->paEscEols[pCompiler->iEscEol].offEsc)
6077 {
6078 cch += pCompiler->paEscEols[pCompiler->iEscEol].offEol
6079 - pCompiler->paEscEols[pCompiler->iEscEol].offEsc
6080 + pCompiler->cchEolSeq;
6081 pCompiler->iEscEol++;
6082 }
6083 }
6084 }
6085 else if (cOpen == 1)
6086 kmk_cc_eval_fatal(pCompiler, &pchWord[cchStart], "Variable reference is missing '%c'", chClose);
6087 else
6088 kmk_cc_eval_fatal(pCompiler, &pchWord[cchStart],
6089 "%u variable references are missing '%c'", cOpen, chClose);
6090 }
6091 }
6092 /* Single char variable name. */
6093 else if (!KMK_CC_EVAL_IS_SPACE(chOpen))
6094 { /* likely */ }
6095 else
6096 kmk_cc_eval_fatal(pCompiler, &pchWord[cch], "Expected variable name after '$', not end of line");
6097 }
6098 else
6099 kmk_cc_eval_fatal(pCompiler, &pchWord[cch], "Neither recipe nor variable assignment");
6100 fPlainVarNm = 0;
6101 cchSubprog += cch - offStart;
6102 }
6103 /* Check out potential recipe, simple assignment or DOS drive letter separator. */
6104 else if (ch == ':')
6105 {
6106 if ( cch + 1 < cchLeft
6107 && pchWord[cch + 1] != '=')
6108 {
6109 cchVarNm = cch;
6110 pchWord += cch;
6111 cchLeft -= cch;
6112 break;
6113 }
6114#ifdef HAVE_DOS_PATHS
6115 /* Don't confuse the first colon in:
6116 C:/Windows/System32/Kernel32.dll: C:/Windows/System32/NtDll.dll
6117 for a recipe, it is only the second one which counts. */
6118 if ( cch == 1
6119 && isalpha((unsigned char)pchWord[0]))
6120 cch++;
6121 else
6122#endif
6123 if (!fQualifiers)
6124 return kmk_cc_eval_handle_recipe_cont_colon(pCompiler, pchWord, cch,
6125 fPlainVarNm
6126 ? kKmkCcEvalToken_WordPlain : kKmkCcEvalToken_WordWithDollar,
6127 pchWord + cch, cchLeft - cch);
6128 /** @todo we may have words already preparsed here so restarting is easy... */
6129 return 0; /* retry with preceeding keywords */
6130 }
6131 /* Check out assignment operator. */
6132 else if (ch == '=')
6133 {
6134 if (cch > 0)
6135 {
6136 char chPrev = pchWord[cch - 1];
6137 if (chPrev == ':' || chPrev == '+' || chPrev == '?' || chPrev == '<')
6138 cch--;
6139 cchVarNm = cch;
6140 pchWord += cch;
6141 cchLeft -= cch;
6142 break;
6143 }
6144 kmk_cc_eval_fatal(pCompiler, pchWord, "Empty variable name.");
6145 }
6146 /* Check out potential escaped EOL sequence. */
6147 else if (ch == '\\')
6148 {
6149 unsigned const iEscEol = pCompiler->iEscEol;
6150 if (iEscEol >= pCompiler->cEscEols)
6151 cch++;
6152 else
6153 {
6154 size_t offCur = &pchWord[cch] - pCompiler->pszContent;
6155 if (offCur < pCompiler->paEscEols[iEscEol].offEol)
6156 cch++;
6157 else
6158 {
6159 cchVarNm = cch;
6160 KMK_CC_ASSERT(offCur == pCompiler->paEscEols[iEscEol].offEol);
6161 cch = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq - offCur;
6162 pCompiler->iEscEol = iEscEol + 1;
6163 pchWord += cch;
6164 cchLeft -= cch;
6165 KMK_CC_EVAL_SKIP_SPACES(pCompiler, pchWord, cchLeft);
6166 break;
6167 }
6168 }
6169 }
6170 else
6171 KMK_CC_ASSERT(0);
6172 }
6173
6174 /*
6175 * Check for assignment operator.
6176 */
6177 if (cchLeft)
6178 {
6179 size_t cchValue;
6180 PKMKCCEVALASSIGN pInstr;
6181 KMKCCEVALINSTR enmOpCode;
6182 int fPlainValue;
6183 char *pszValue;
6184
6185 ch = *pchWord;
6186 if (ch == '=')
6187 {
6188 enmOpCode = kKmkCcEvalInstr_assign_recursive;
6189 pchWord++;
6190 cchLeft--;
6191 }
6192 else if (cchLeft >= 2 && pchWord[1] == '=')
6193 {
6194 if (ch == ':')
6195 enmOpCode = kKmkCcEvalInstr_assign_simple;
6196 else if (ch == '+')
6197 enmOpCode = kKmkCcEvalInstr_assign_append;
6198 else if (ch == '<')
6199 enmOpCode = kKmkCcEvalInstr_assign_prepend;
6200 else if (ch == '?')
6201 enmOpCode = kKmkCcEvalInstr_assign_if_new;
6202 else if (!fQualifiers)
6203 return kmk_cc_eval_handle_recipe_cont_2nd_word(pCompiler, pchVarNm, cchVarNm, pchWord, cchLeft);
6204 else
6205 return 0; /* retry without preceding keywords */
6206 pchWord += 2;
6207 cchLeft -= 2;
6208 }
6209 else if (!fQualifiers)
6210 return kmk_cc_eval_handle_recipe_cont_2nd_word(pCompiler, pchVarNm, cchVarNm, pchWord, cchLeft);
6211 else
6212 return 0; /* retry without preceding keywords */
6213
6214 /*
6215 * Skip leading spaces, if any and prep the value for copying.
6216 */
6217 KMK_CC_EVAL_SKIP_SPACES(pCompiler, pchWord, cchLeft);
6218 cchValue = kmk_cc_eval_prep_normal_line(pCompiler, pchWord, cchLeft);
6219 fPlainValue = memchr(pchWord, '$', cchLeft) == NULL;
6220
6221 /*
6222 * Emit the instruction.
6223 */
6224 kmk_cc_eval_end_of_recipe(pCompiler, pchWord);
6225
6226 pInstr = (PKMKCCEVALASSIGN)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
6227 pInstr->Core.enmOpcode = enmOpCode;
6228 pInstr->Core.iLine = pCompiler->iLine;
6229 pInstr->fExport = (fQualifiers & KMK_CC_EVAL_QUALIFIER_EXPORT) != 0;
6230 pInstr->fOverride = (fQualifiers & KMK_CC_EVAL_QUALIFIER_OVERRIDE) != 0;
6231 pInstr->fPrivate = (fQualifiers & KMK_CC_EVAL_QUALIFIER_PRIVATE) != 0;
6232 pInstr->fLocal = (fQualifiers & KMK_CC_EVAL_QUALIFIER_LOCAL) != 0;
6233
6234 /* We copy the value before messing around with the variable name since
6235 we have to do more iEolEsc saves & restores the other way around. */
6236 pszValue = kmk_cc_eval_strdup_prepped(pCompiler, cchValue);
6237 if (fPlainVarNm)
6238 pchVarNm = strcache2_add(&variable_strcache, pchVarNm, cchVarNm);
6239 else
6240 {
6241 pCompiler->iEscEol = iEscEolVarNm;
6242 cchVarNm = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchVarNm, cchVarNm);
6243 pchVarNm = kmk_cc_eval_strdup_prepped(pCompiler, cchVarNm);
6244 }
6245 kmk_cc_block_realign(pCompiler->ppBlockTail);
6246 KMK_CC_EVAL_DPRINTF(("%s: '%s' '%s'\n", g_apszEvalInstrNms[enmOpCode], pchVarNm, pszValue));
6247
6248 kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Variable, pchVarNm, cchVarNm, fPlainVarNm);
6249 kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Value, pszValue, cchValue, fPlainValue);
6250
6251 pInstr->pNext = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail);
6252 }
6253 /*
6254 * This could be one or more function calls.
6255 */
6256 else if (!fPlainVarNm && cchVarNm == cchSubprog && fQualifiers == 0)
6257 return kmk_cc_eval_emit_expand(pCompiler, pchVarNm, cchVarNm, iEscEolVarNm);
6258 else if (!fPlainVarNm)
6259 kmk_cc_eval_fatal(pCompiler, pchWord,
6260 "Not variable assignment. Could be a complicated indirect recipe definition, however that's currently not supported.");
6261 else
6262 kmk_cc_eval_fatal(pCompiler, pchWord, "Neither recipe nor variable assignment");
6263 return 1;
6264}
6265
6266
6267/**
6268 * Parses a 'local [override] variable = value', 'local define variable', and
6269 * 'local undefine variable [...]' expressions.
6270 *
6271 * The 'local' directive must be first and it does not permit any qualifiers at
6272 * the moment. Should any be added later, they will have to come after 'local'.
6273 *
6274 * @returns 1 to indicate we've handled a keyword (see
6275 * kmk_cc_eval_try_handle_keyword).
6276 * @param pCompiler The compiler state.
6277 * @param pchWord First char after 'local'.
6278 * @param cchLeft The number of chars left to parse on this line.
6279 * @param fQualifiers The qualifiers.
6280 */
6281static int kmk_cc_eval_do_var_local(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
6282{
6283 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
6284 if (cchLeft)
6285 {
6286 /*
6287 * Check for 'local define' and 'local undefine'
6288 */
6289 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6)) /* final */
6290 return kmk_cc_eval_do_var_define(pCompiler, pchWord + 6, cchLeft + 6, KMK_CC_EVAL_QUALIFIER_LOCAL);
6291 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8)) /* final */
6292 return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 8, cchLeft + 8, KMK_CC_EVAL_QUALIFIER_LOCAL);
6293
6294 /*
6295 * Simpler to just join paths with the rest here, even if we could
6296 * probably optimize the parsing a little if we liked.
6297 */
6298 return kmk_cc_eval_handle_assignment_or_recipe(pCompiler, pchWord, cchLeft, KMK_CC_EVAL_QUALIFIER_LOCAL);
6299 }
6300 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected variable name, assignment operator and value after 'local'");
6301 return 1;
6302}
6303
6304
6305/**
6306 * We've found one variable qualification keyword, now continue parsing and see
6307 * if this is some kind of variable assignment expression or not.
6308 *
6309 * @returns 1 if variable assignment, 0 if not.
6310 * @param pCompiler The compiler state.
6311 * @param pchWord First char after the first qualifier.
6312 * @param cchLeft The number of chars left to parse on this line.
6313 * @param fQualifiers The qualifier.
6314 */
6315static int kmk_cc_eval_try_handle_var_with_keywords(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft,
6316 unsigned fQualifiers)
6317{
6318 for (;;)
6319 {
6320 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
6321 if (cchLeft)
6322 {
6323 char ch = *pchWord;
6324 if (KMK_CC_EVAL_IS_1ST_IN_VARIABLE_KEYWORD(ch))
6325 {
6326 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6)) /* final */
6327 return kmk_cc_eval_do_var_define(pCompiler, pchWord + 6, cchLeft - 6, fQualifiers);
6328
6329 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8)) /* final */
6330 return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 8, cchLeft -86, fQualifiers);
6331
6332 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "unexport", 8)) /* final */
6333 return kmk_cc_eval_do_var_unexport(pCompiler, pchWord + 8, cchLeft - 8, fQualifiers);
6334
6335 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6))
6336 {
6337 if (!(fQualifiers & KMK_CC_EVAL_QUALIFIER_EXPORT))
6338 fQualifiers |= KMK_CC_EVAL_QUALIFIER_EXPORT;
6339 else
6340 kmk_cc_eval_warn(pCompiler, pchWord, "'export' qualifier repeated");
6341 pchWord += 6;
6342 cchLeft -= 6;
6343 continue;
6344 }
6345
6346 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8))
6347 {
6348 if (!(fQualifiers & KMK_CC_EVAL_QUALIFIER_OVERRIDE))
6349 fQualifiers |= KMK_CC_EVAL_QUALIFIER_OVERRIDE;
6350 else
6351 kmk_cc_eval_warn(pCompiler, pchWord, "'override' qualifier repeated");
6352 pchWord += 8;
6353 cchLeft -= 8;
6354 continue;
6355 }
6356
6357 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7))
6358 {
6359 if (!(fQualifiers & KMK_CC_EVAL_QUALIFIER_PRIVATE))
6360 fQualifiers |= KMK_CC_EVAL_QUALIFIER_PRIVATE;
6361 else
6362 kmk_cc_eval_warn(pCompiler, pchWord, "'private' qualifier repeated");
6363 pchWord += 7;
6364 cchLeft -= 7;
6365 continue;
6366 }
6367 }
6368
6369 /*
6370 * Not a keyword, likely variable name followed by an assignment
6371 * operator and a value. Do a rough check for the assignment operator
6372 * and join paths with the unqualified assignment handling code.
6373 */
6374 {
6375 const char *pchEqual = (const char *)memchr(pchWord, '=', cchLeft);
6376 if (pchEqual)
6377 return kmk_cc_eval_handle_assignment_or_recipe(pCompiler, pchWord, cchLeft, fQualifiers);
6378 }
6379 return 0;
6380 }
6381 else
6382 kmk_cc_eval_fatal(pCompiler, NULL,
6383 "Expected assignment operator or variable directive after variable qualifier(s)\n");
6384 }
6385}
6386
6387
6388/**
6389 * Parses 'export [variable]' and 'export [qualifiers] variable = value'
6390 * expressions.
6391 *
6392 * When we find the 'export' directive at the start of a line, we need to
6393 * continue parsing with till we can tell the difference between the two forms.
6394 *
6395 * @returns 1 to indicate we've handled a keyword (see
6396 * kmk_cc_eval_try_handle_keyword).
6397 * @param pCompiler The compiler state.
6398 * @param pchWord First char after 'define'.
6399 * @param cchLeft The number of chars left to parse on this line.
6400 */
6401static int kmk_cc_eval_handle_var_export(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
6402{
6403 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
6404
6405 if (cchLeft)
6406 {
6407 unsigned iSavedEscEol;
6408 unsigned cWords;
6409
6410 /*
6411 * We need to figure out whether this is an assignment or a export statement,
6412 * in the latter case join paths with 'export' and 'undefine'.
6413 */
6414 const char *pchEqual = (const char *)memchr(pchWord, '=', cchLeft);
6415 if (!pchEqual)
6416 return kmk_cc_eval_do_with_variable_list(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_export, 0 /*fQualifiers*/);
6417
6418 /*
6419 * Found an '=', could be an assignment. Let's take the easy way out
6420 * and just parse the whole statement into words like we would do if
6421 * it wasn't an assignment, and then check the words out for
6422 * assignment keywords and operators.
6423 */
6424 iSavedEscEol = pCompiler->iEscEol;
6425 cWords = kmk_cc_eval_parse_words(pCompiler, pchWord, cchLeft);
6426 if (cWords)
6427 {
6428 PKMKCCEVALVARIABLES pInstr;
6429 PKMKCCEVALWORD pWord = pCompiler->paWords;
6430 unsigned iWord = 0;
6431 while (iWord < cWords)
6432 {
6433 /* Trailing assignment operator or terminal assignment directive ('undefine'
6434 and 'unexport' makes no sense here but GNU make ignores that). */
6435 if ( ( pWord->cchWord > 1
6436 && pWord->pchWord[pWord->cchWord - 1] == '=')
6437 || KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "define", 6)
6438 || KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "undefine", 8)
6439 || KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "unexport", 8) )
6440 {
6441 pCompiler->iEscEol = iSavedEscEol;
6442 return kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord, cchLeft, KMK_CC_EVAL_QUALIFIER_EXPORT);
6443 }
6444
6445 /* If not a variable assignment qualifier, it must be a variable name
6446 followed by an assignment operator. */
6447 if (iWord + 1 < cWords)
6448 {
6449 if ( !KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "export", 6)
6450 && !KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "private", 7)
6451 && !KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "override", 8))
6452 {
6453 pWord++;
6454 if ( pWord->cchWord > 0
6455 && ( pWord->pchWord[0] == '='
6456 || ( pWord->cchWord > 1
6457 && pWord->pchWord[1] == '='
6458 && ( pWord->pchWord[0] == ':'
6459 || pWord->pchWord[0] == '+'
6460 || pWord->pchWord[0] == '?'
6461 || pWord->pchWord[0] == '<') ) ) )
6462 {
6463 pCompiler->iEscEol = iSavedEscEol;
6464 return kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord, cchLeft,
6465 KMK_CC_EVAL_QUALIFIER_EXPORT);
6466 }
6467 break;
6468 }
6469 }
6470 else
6471 break;
6472 /* next */
6473 pWord++;
6474 iWord++;
6475 }
6476
6477 /*
6478 * It's not an assignment.
6479 * (This is the same as kmk_cc_eval_do_with_variable_list does.)
6480 */
6481 pInstr = (PKMKCCEVALVARIABLES)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, KMKCCEVALVARIABLES_SIZE(cWords));
6482 pInstr->Core.enmOpcode = kKmkCcEvalInstr_export;
6483 pInstr->Core.iLine = pCompiler->iLine;
6484 pInstr->cVars = cWords;
6485 kmk_cc_eval_init_spp_array_from_duplicated_words(pCompiler, cWords, pCompiler->paWords, pInstr->aVars);
6486 kmk_cc_block_realign(pCompiler->ppBlockTail);
6487 }
6488 else
6489 KMK_CC_ASSERT(0);
6490 }
6491 else
6492 {
6493 /*
6494 * We're exporting all variables.
6495 */
6496 PKMKCCEVALCORE pInstr = kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
6497 pInstr->enmOpcode = kKmkCcEvalInstr_export_all;
6498 pInstr->iLine = pCompiler->iLine;
6499 }
6500 return 1;
6501}
6502
6503
6504/**
6505 * When entering this function we know that the first two character in the first
6506 * word both independently occurs in keywords.
6507 *
6508 * @returns 1 if make directive or qualified variable assignment, 0 if neither.
6509 * @param pCompiler The compiler state.
6510 * @param ch The first char.
6511 * @param pchWord Pointer to the first word.
6512 * @param cchLeft Number of characters left to parse starting at
6513 * @a cchLeft.
6514 */
6515int kmk_cc_eval_try_handle_keyword(PKMKCCEVALCOMPILER pCompiler, char ch, const char *pchWord, size_t cchLeft)
6516{
6517 unsigned iSavedEscEol = pCompiler->iEscEol;
6518
6519 KMK_CC_ASSERT(cchLeft >= 2);
6520 KMK_CC_ASSERT(ch == pchWord[0]);
6521 KMK_CC_ASSERT(KMK_CC_EVAL_IS_1ST_IN_KEYWORD(pchWord[0]));
6522 KMK_CC_ASSERT(KMK_CC_EVAL_IS_2ND_IN_KEYWORD(pchWord[1]));
6523
6524 /*
6525 * If it's potentially a variable related keyword, check that out first.
6526 */
6527 if (KMK_CC_EVAL_IS_1ST_IN_VARIABLE_KEYWORD(ch))
6528 {
6529 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "local", 5))
6530 return kmk_cc_eval_do_var_local(pCompiler, pchWord + 5, cchLeft - 5);
6531 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6))
6532 return kmk_cc_eval_do_var_define(pCompiler, pchWord + 6, cchLeft - 6, 0);
6533 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6))
6534 return kmk_cc_eval_handle_var_export(pCompiler, pchWord + 6, cchLeft - 6);
6535 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8))
6536 return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 8, cchLeft - 8, 0);
6537 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "unexport", 8))
6538 return kmk_cc_eval_do_var_unexport(pCompiler, pchWord + 8, cchLeft - 8, 0);
6539 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8))
6540 {
6541 if (kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord + 8, cchLeft - 8, KMK_CC_EVAL_QUALIFIER_OVERRIDE))
6542 return 1;
6543 pCompiler->iEscEol = iSavedEscEol;
6544 }
6545 else if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7))
6546 {
6547 if (kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord + 7, cchLeft - 7, KMK_CC_EVAL_QUALIFIER_PRIVATE))
6548 return 1;
6549 pCompiler->iEscEol = iSavedEscEol;
6550 }
6551 }
6552
6553 /*
6554 * Check out the other keywords.
6555 */
6556 if (ch == 'i') /* Lots of directives starting with 'i'. */
6557 {
6558 char ch2 = pchWord[1];
6559 pchWord += 2;
6560 cchLeft -= 2;
6561
6562 /* 'if...' */
6563 if (ch2 == 'f')
6564 {
6565 if (KMK_CC_EVAL_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
6566 return kmk_cc_eval_do_if(pCompiler, pchWord, cchLeft, 0 /* in else */);
6567
6568 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "eq", 2))
6569 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 2, cchLeft - 2, 0 /* in else */, 1 /* positive */);
6570
6571 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "def", 3))
6572 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 1 /* positive */);
6573
6574 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "neq", 3))
6575 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 0 /* positive */);
6576
6577 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "1of", 3))
6578 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 1 /* positive */);
6579
6580 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "ndef", 4))
6581 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 4, cchLeft - 4, 0 /* in else */, 0 /* positive */);
6582
6583 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "n1of", 4))
6584 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 4, cchLeft - 4, 0 /* in else */, 0 /* positive */);
6585 }
6586 /* include... */
6587 else if (ch2 == 'n' && cchLeft >= 5 && KMK_CC_WORD_COMP_CONST_5(pchWord, "clude") ) /* 'in...' */
6588 {
6589 pchWord += 5;
6590 cchLeft -= 5;
6591 if (KMK_CC_EVAL_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
6592 return kmk_cc_eval_do_include(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_include);
6593 if (cchLeft >= 3 && KMK_CC_WORD_COMP_CONST_3(pchWord, "dep"))
6594 {
6595 pchWord += 3;
6596 cchLeft -= 3;
6597 if (KMK_CC_EVAL_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
6598 return kmk_cc_eval_do_include(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_includedep);
6599 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-queue", 6))
6600 return kmk_cc_eval_do_include(pCompiler, pchWord + 6, cchLeft - 6, kKmkCcEvalInstr_includedep_queue);
6601 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-flush", 6))
6602 return kmk_cc_eval_do_include(pCompiler, pchWord + 6, cchLeft - 6, kKmkCcEvalInstr_includedep_flush);
6603 }
6604 }
6605 }
6606 else if (ch == 'e') /* A few directives starts with 'e'. */
6607 {
6608 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "else", 4))
6609 return kmk_cc_eval_do_else(pCompiler, pchWord + 4, cchLeft - 4);
6610 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "endif", 5))
6611 return kmk_cc_eval_do_endif(pCompiler, pchWord + 5, cchLeft - 5);
6612 /* export and endef are handled elsewhere, though stray endef's may end up here... */
6613 KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6));
6614
6615 }
6616 else /* the rest. */
6617 {
6618 if ( KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "sinclude", 8)
6619 || KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-include", 8))
6620 return kmk_cc_eval_do_include(pCompiler, pchWord + 8, cchLeft - 8, kKmkCcEvalInstr_include_silent);
6621 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "vpath", 5))
6622 return kmk_cc_eval_do_vpath(pCompiler, pchWord + 5, cchLeft - 5);
6623
6624 KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "local", 5));
6625 KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6));
6626 KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7));
6627 KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8));
6628 KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "unexport", 8));
6629 KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8));
6630 }
6631
6632 pCompiler->iEscEol = iSavedEscEol;
6633 return 0;
6634}
6635
6636
6637
6638
6639static int kmk_cc_eval_compile_worker(PKMKCCEVALPROG pEvalProg, const char *pszContent, size_t cchContent, unsigned iLine)
6640{
6641 const char *pchTmp;
6642
6643 /*
6644 * Compiler state.
6645 */
6646 KMKCCEVALCOMPILER Compiler;
6647 kmk_cc_eval_init_compiler(&Compiler, pEvalProg, iLine, pszContent, cchContent);
6648 KMK_CC_EVAL_DPRINTF(("\nkmk_cc_eval_compile_worker - begin (%s/%s/%d)\n", pEvalProg->pszFilename, pEvalProg->pszVarName, iLine));
6649
6650 {
6651 /*
6652 * Line state.
6653 */
6654 size_t cchLine; /* The length of the current line (w/o comments). */
6655 size_t offNext = 0; /* The offset of the next line. */
6656 size_t off = 0; /* The offset into pszContent of the current line. */
6657
6658 /* Try for some register/whatever optimzations. */
6659 int const chFirstEol = Compiler.chFirstEol;
6660 size_t const cchEolSeq = Compiler.cchEolSeq;
6661
6662 /*
6663 * Process input lines.
6664 *
6665 * The code here concerns itself with getting the next line in an efficient
6666 * manner, very basic classification and trying out corresponding handlers.
6667 * The real work is done in the handlers.
6668 */
6669 while (offNext < cchContent)
6670 {
6671 size_t offFirstWord;
6672
6673 /*
6674 * Find the end of the next line.
6675 */
6676 KMK_CC_ASSERT(off == offNext);
6677
6678 /* Simple case: No escaped EOL, nor the end of the input. */
6679 pchTmp = (const char *)memchr(&pszContent[offNext], chFirstEol, cchContent - offNext);
6680 if ( pchTmp
6681 && ( &pszContent[offNext] == pchTmp
6682 || pchTmp[-1] != '\\') )
6683 {
6684 if ( cchEolSeq == 1
6685 || pchTmp[1] == Compiler.chSecondEol)
6686 {
6687 /* Frequent: Blank line. */
6688 if (&pszContent[offNext] == pchTmp)
6689 {
6690 KMK_CC_EVAL_DPRINTF(("#%03u: <empty>\n", Compiler.iLine));
6691 Compiler.iLine++;
6692 off = offNext += cchEolSeq;
6693 continue;
6694 }
6695 if (pszContent[offNext] == '#')
6696 {
6697 KMK_CC_EVAL_DPRINTF(("#%03u: <comment-col-0>\n", Compiler.iLine));
6698 Compiler.iLine++;
6699 offNext = pchTmp - pszContent;
6700 off = offNext += cchEolSeq;
6701 continue;
6702 }
6703
6704 offNext = pchTmp - pszContent;
6705 cchLine = offNext - off;
6706
6707 offFirstWord = off;
6708 while (offFirstWord < offNext && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord]))
6709 offFirstWord++;
6710
6711 offNext += cchEolSeq;
6712 Compiler.cEscEols = 0;
6713 Compiler.iEscEol = 0;
6714 }
6715 else
6716 kmk_cc_eval_fatal_eol(&Compiler, pchTmp, Compiler.iLine, off);
6717 }
6718 /* The complicated, less common cases. */
6719 else
6720 {
6721 Compiler.cEscEols = 0;
6722 Compiler.iEscEol = 0;
6723 offFirstWord = offNext;
6724 for (;;)
6725 {
6726 if (offFirstWord == offNext)
6727 {
6728 size_t offEol = off + cchLine;
6729 while (offFirstWord < offEol && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord]))
6730 offFirstWord++;
6731 }
6732
6733 if (pchTmp)
6734 {
6735 if ( cchEolSeq == 1
6736 || pchTmp[1] == Compiler.chSecondEol)
6737 {
6738 size_t offEsc;
6739 if (offFirstWord != offNext)
6740 offNext = pchTmp - pszContent;
6741 else
6742 {
6743 offNext = pchTmp - pszContent;
6744 while (offFirstWord < offNext && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord]))
6745 offFirstWord++;
6746 }
6747
6748
6749 /* Is it an escape sequence? */
6750 if ( !offNext
6751 || pchTmp[-1] != '\\')
6752 {
6753 cchLine = offNext - off;
6754 offNext += cchEolSeq;
6755 break;
6756 }
6757 if (offNext < 2 || pchTmp[-2] != '\\')
6758 offEsc = offNext - 1;
6759 else
6760 {
6761 /* Count how many backslashes there are. Must be odd number to be an escape
6762 sequence. Normally we keep half of them, except for command lines. */
6763 size_t cSlashes = 2;
6764 while (offNext >= cSlashes && pchTmp[0 - cSlashes] == '\\')
6765 cSlashes--;
6766 if (!(cSlashes & 1))
6767 {
6768 cchLine = offNext - off;
6769 offNext += cchEolSeq;
6770 break;
6771 }
6772 offEsc = offNext - (cSlashes >> 1);
6773 }
6774
6775 /* Record it. */
6776 if (Compiler.cEscEols < Compiler.cEscEolsAllocated) { /* likely */ }
6777 else
6778 {
6779 KMK_CC_ASSERT(Compiler.cEscEols == Compiler.cEscEolsAllocated);
6780 Compiler.cEscEolsAllocated = Compiler.cEscEolsAllocated
6781 ? Compiler.cEscEolsAllocated * 2 : 2;
6782 Compiler.paEscEols = (PKMKCCEVALESCEOL)xrealloc(Compiler.paEscEols,
6783 Compiler.cEscEolsAllocated
6784 * sizeof(Compiler.paEscEols[0]));
6785 }
6786 Compiler.paEscEols[Compiler.cEscEols].offEsc = offEsc;
6787 Compiler.paEscEols[Compiler.cEscEols].offEol = offNext;
6788 Compiler.cEscEols++;
6789
6790 /* Advance. */
6791 offNext += cchEolSeq;
6792 if (offFirstWord == offEsc)
6793 {
6794 offFirstWord = offNext;
6795 Compiler.iEscEol++;
6796 }
6797 }
6798 else
6799 kmk_cc_eval_fatal_eol(&Compiler, pchTmp, Compiler.iLine, off);
6800 }
6801 else
6802 {
6803 /* End of input. Happens only once per compilation, nothing to optimize for. */
6804 if (offFirstWord == offNext)
6805 while (offFirstWord < cchContent && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord]))
6806 offFirstWord++;
6807 offNext = cchContent;
6808 cchLine = cchContent - off;
6809 break;
6810 }
6811 pchTmp = (const char *)memchr(&pszContent[offNext], chFirstEol, cchContent - offNext);
6812 }
6813 }
6814 KMK_CC_ASSERT(offNext <= cchContent);
6815 KMK_CC_ASSERT(offNext >= off + cchLine);
6816 KMK_CC_ASSERT(off + cchLine <= cchContent && cchLine <= cchContent);
6817 KMK_CC_ASSERT(offFirstWord <= off + cchLine);
6818 KMK_CC_ASSERT(offFirstWord >= off);
6819 KMK_CC_ASSERT(pszContent[offFirstWord] != ' ' && pszContent[offFirstWord] != '\t');
6820
6821 KMK_CC_EVAL_DPRINTF(("#%03u: %*.*s\n", Compiler.iLine, (int)cchLine, (int)cchLine, &pszContent[off]));
6822
6823 /*
6824 * Skip blank lines.
6825 */
6826 if (offFirstWord < off + cchLine)
6827 {
6828 /*
6829 * Command? Ignore command prefix if no open recipe (SunOS 4 behavior).
6830 */
6831 if ( pszContent[off] == Compiler.chCmdPrefix
6832 && (Compiler.pRecipe || Compiler.fNoTargetRecipe))
6833 {
6834 if (!Compiler.fNoTargetRecipe)
6835 kmk_cc_eval_handle_command(&Compiler, &pszContent[off], cchLine);
6836 }
6837 /*
6838 * Since it's not a command line, we can now skip comment lines
6839 * even with a tab indentation. If it's not a comment line, we
6840 * tentatively strip any trailing comment.
6841 */
6842 else if (pszContent[offFirstWord] != '#')
6843 {
6844 const char *pchWord = &pszContent[offFirstWord];
6845 size_t cchLeft = off + cchLine - offFirstWord;
6846 char ch;
6847
6848 Compiler.cchLineWithComments = cchLine;
6849 pchTmp = (const char *)memchr(pchWord, '#', cchLeft);
6850 if (pchTmp)
6851 {
6852 cchLeft = pchTmp - pchWord;
6853 cchLine = pchTmp - &pszContent[off];
6854 }
6855 Compiler.cchLine = cchLine;
6856 Compiler.offLine = off;
6857
6858#ifdef KMK_CC_STRICT
6859 Compiler.cWords = 0x424242;
6860#endif
6861
6862 /*
6863 * If not a directive or variable qualifier, it's either a variable
6864 * assignment or a recipe.
6865 */
6866 ch = *pchWord;
6867 if ( !KMK_CC_EVAL_IS_1ST_IN_KEYWORD(ch)
6868 || !KMK_CC_EVAL_IS_2ND_IN_KEYWORD(pchWord[1])
6869 || !kmk_cc_eval_try_handle_keyword(&Compiler, ch, pchWord, cchLeft) )
6870 {
6871 pchTmp = (const char *)memchr(pchWord, '=', cchLeft);
6872 if (pchTmp)
6873 kmk_cc_eval_handle_assignment_or_recipe(&Compiler, pchWord, cchLeft, 0 /*fQualifiers*/);
6874 else
6875 kmk_cc_eval_handle_recipe(&Compiler, pchWord, cchLeft);
6876 }
6877 /* else: handled a keyword expression */
6878 }
6879 }
6880
6881 /*
6882 * Advance to the next line.
6883 */
6884 off = offNext;
6885 Compiler.iLine += Compiler.cEscEols + 1;
6886 }
6887 }
6888
6889 /*
6890 * Check whether
6891 */
6892
6893 kmk_cc_eval_delete_compiler(&Compiler);
6894 KMK_CC_EVAL_DPRINTF(("kmk_cc_eval_compile_worker - done (%s/%s)\n\n", pEvalProg->pszFilename, pEvalProg->pszVarName));
6895 return 0;
6896}
6897
6898
6899
6900static PKMKCCEVALPROG kmk_cc_eval_compile(const char *pszContent, size_t cchContent,
6901 const char *pszFilename, unsigned iLine, const char *pszVarName)
6902{
6903 /*
6904 * Estimate block size, allocate one and initialize it.
6905 */
6906 PKMKCCEVALPROG pEvalProg;
6907 PKMKCCBLOCK pBlock;
6908 pEvalProg = kmk_cc_block_alloc_first(&pBlock, sizeof(*pEvalProg), cchContent / 32); /** @todo adjust */
6909 if (pEvalProg)
6910 {
6911 pEvalProg->pBlockTail = pBlock;
6912 pEvalProg->pFirstInstr = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(pBlock);
6913 pEvalProg->pszFilename = pszFilename ? pszFilename : "<unknown>";
6914 pEvalProg->pszVarName = pszVarName;
6915 pEvalProg->cRefs = 1;
6916#ifdef KMK_CC_STRICT
6917 pEvalProg->uInputHash = kmk_cc_debug_string_hash_n(0, pszContent, cchContent);
6918#endif
6919
6920 /*
6921 * Do the actual compiling.
6922 */
6923#ifdef CONFIG_WITH_EVAL_COMPILER
6924 if (kmk_cc_eval_compile_worker(pEvalProg, pszContent, cchContent, iLine) == 0)
6925#else
6926 if (0)
6927#endif
6928 {
6929#ifdef KMK_CC_WITH_STATS
6930 pBlock = pEvalProg->pBlockTail;
6931 if (!pBlock->pNext)
6932 g_cSingleBlockEvalProgs++;
6933 else if (!pBlock->pNext->pNext)
6934 g_cTwoBlockEvalProgs++;
6935 else
6936 g_cMultiBlockEvalProgs++;
6937 for (; pBlock; pBlock = pBlock->pNext)
6938 {
6939 g_cBlocksAllocatedEvalProgs++;
6940 g_cbAllocatedEvalProgs += pBlock->cbBlock;
6941 g_cbUnusedMemEvalProgs += pBlock->cbBlock - pBlock->offNext;
6942 }
6943#endif
6944 return pEvalProg;
6945 }
6946 kmk_cc_block_free_list(pEvalProg->pBlockTail);
6947 }
6948 return NULL;
6949}
6950
6951
6952/**
6953 * Compiles a variable direct evaluation as is, setting v->evalprog on success.
6954 *
6955 * @returns Pointer to the program on success, NULL if no program was created.
6956 * @param pVar Pointer to the variable.
6957 */
6958struct kmk_cc_evalprog *kmk_cc_compile_variable_for_eval(struct variable *pVar)
6959{
6960 PKMKCCEVALPROG pEvalProg = pVar->evalprog;
6961 if (!pEvalProg)
6962 {
6963#ifdef CONFIG_WITH_EVAL_COMPILER
6964 pEvalProg = kmk_cc_eval_compile(pVar->value, pVar->value_length,
6965 pVar->fileinfo.filenm, pVar->fileinfo.lineno, pVar->name);
6966 pVar->evalprog = pEvalProg;
6967#endif
6968 g_cVarForEvalCompilations++;
6969 }
6970 return pEvalProg;
6971}
6972
6973
6974/**
6975 * Compiles a makefile for
6976 *
6977 * @returns Pointer to the program on success, NULL if no program was created.
6978 * @param pVar Pointer to the variable.
6979 */
6980struct kmk_cc_evalprog *kmk_cc_compile_file_for_eval(FILE *pFile, const char *pszFilename)
6981{
6982 PKMKCCEVALPROG pEvalProg;
6983
6984 /*
6985 * Read the entire file into a zero terminate memory buffer.
6986 */
6987 size_t cchContent = 0;
6988 char *pszContent = NULL;
6989 struct stat st;
6990 if (!fstat(fileno(pFile), &st))
6991 {
6992 if ( st.st_size > (off_t)KMK_CC_EVAL_MAX_COMPILE_SIZE
6993 && st.st_size < 0)
6994 fatal(NULL, _("Makefile too large to compile: %ld bytes (%#lx) - max %uMB"),
6995 (long)st.st_size, (long)st.st_size, KMK_CC_EVAL_MAX_COMPILE_SIZE / 1024 / 1024);
6996 cchContent = (size_t)st.st_size;
6997 pszContent = (char *)xmalloc(cchContent + 1);
6998
6999 cchContent = fread(pszContent, 1, cchContent, pFile);
7000 if (ferror(pFile))
7001 fatal(NULL, _("Read error: %s"), strerror(errno));
7002 }
7003 else
7004 {
7005 size_t cbAllocated = 2048;
7006 do
7007 {
7008 cbAllocated *= 2;
7009 if (cbAllocated > KMK_CC_EVAL_MAX_COMPILE_SIZE)
7010 fatal(NULL, _("Makefile too large to compile: max %uMB"), KMK_CC_EVAL_MAX_COMPILE_SIZE / 1024 / 1024);
7011 pszContent = (char *)xrealloc(pszContent, cbAllocated);
7012 cchContent += fread(&pszContent[cchContent], 1, cbAllocated - 1 - cchContent, pFile);
7013 if (ferror(pFile))
7014 fatal(NULL, _("Read error: %s"), strerror(errno));
7015 } while (!feof(pFile));
7016 }
7017 pszContent[cchContent] = '\0';
7018
7019 /*
7020 * Call common function to do the compilation.
7021 */
7022 pEvalProg = kmk_cc_eval_compile(pszContent, cchContent, pszFilename, 1, NULL /*pszVarName*/);
7023 g_cFileForEvalCompilations++;
7024
7025 free(pszContent);
7026 if (!pEvalProg)
7027 fseek(pFile, 0, SEEK_SET);
7028 return pEvalProg;
7029}
7030
7031
7032/**
7033 * Equivalent of eval_buffer, only it's using the evalprog of the variable.
7034 *
7035 * @param pVar Pointer to the variable. Must have a program.
7036 */
7037void kmk_exec_eval_variable(struct variable *pVar)
7038{
7039 KMK_CC_ASSERT(pVar->evalprog);
7040 assert(0);
7041}
7042
7043
7044/**
7045 * Worker for eval_makefile.
7046 *
7047 * @param pEvalProg The program pointer.
7048 */
7049void kmk_exec_eval_file(struct kmk_cc_evalprog *pEvalProg)
7050{
7051 KMK_CC_ASSERT(pEvalProg);
7052 assert(0);
7053
7054}
7055
7056
7057
7058/*
7059 *
7060 * Program destruction hooks.
7061 * Program destruction hooks.
7062 * Program destruction hooks.
7063 *
7064 */
7065
7066
7067/**
7068 * Called when a variable with expandprog or/and evalprog changes.
7069 *
7070 * @param pVar Pointer to the variable.
7071 */
7072void kmk_cc_variable_changed(struct variable *pVar)
7073{
7074 PKMKCCEXPPROG pProg = pVar->expandprog;
7075
7076 KMK_CC_ASSERT(pVar->evalprog || pProg);
7077
7078 if (pVar->evalprog)
7079 {
7080 kmk_cc_block_free_list(pVar->evalprog->pBlockTail);
7081 pVar->evalprog = NULL;
7082 }
7083
7084 if (pProg)
7085 {
7086 if (pProg->cRefs == 1)
7087 kmk_cc_block_free_list(pProg->pBlockTail);
7088 else
7089 fatal(NULL, _("Modifying a variable (%s) while its expansion program is running is not supported"), pVar->name);
7090 pVar->expandprog = NULL;
7091 }
7092}
7093
7094
7095/**
7096 * Called when a variable with expandprog or/and evalprog is deleted.
7097 *
7098 * @param pVar Pointer to the variable.
7099 */
7100void kmk_cc_variable_deleted(struct variable *pVar)
7101{
7102 PKMKCCEXPPROG pProg = pVar->expandprog;
7103
7104 KMK_CC_ASSERT(pVar->evalprog || pProg);
7105
7106 if (pVar->evalprog)
7107 {
7108 kmk_cc_block_free_list(pVar->evalprog->pBlockTail);
7109 pVar->evalprog = NULL;
7110 }
7111
7112 if (pProg)
7113 {
7114 if (pProg->cRefs == 1)
7115 kmk_cc_block_free_list(pProg->pBlockTail);
7116 else
7117 fatal(NULL, _("Deleting a variable (%s) while its expansion program is running is not supported"), pVar->name);
7118 pVar->expandprog = NULL;
7119 }
7120}
7121
7122
7123
7124
7125
7126
7127
7128#endif /* CONFIG_WITH_COMPILER */
7129
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use