VirtualBox

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

Last change on this file since 2797 was 2797, checked in by bird, 10 years ago

kmk_cc_exec.c: gcc build fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 200.0 KB
Line 
1#ifdef CONFIG_WITH_COMPILER
2/* $Id: kmk_cc_exec.c 2797 2015-09-19 15:35:39Z bird $ */
3/** @file
4 * kmk_cc - Make "Compiler".
5 */
6
7/*
8 * Copyright (c) 2015 knut st. osmundsen <bird-kBuild-spamx@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 "make.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# else
71# define KMK_CC_ASSERT(a_TrueExpr) assert(a_TrueExpr)
72# endif
73#else
74# define KMK_CC_ASSERT(a_TrueExpr) do {} while (0)
75#endif
76#define KMK_CC_ASSERT_ALIGNED(a_uValue, a_uAlignment) \
77 KMK_CC_ASSERT( ((a_uValue) & ((a_uAlignment) - 1)) == 0 )
78
79
80/** @def KMK_CC_OFFSETOF
81 * Offsetof for simple stuff. */
82#if defined(__GNUC__)
83# define KMK_CC_OFFSETOF(a_Struct, a_Member) __builtin_offsetof(a_Struct, a_Member)
84#else
85# define KMK_CC_OFFSETOF(a_Struct, a_Member) ( (uintptr_t)&( ((a_Struct *)(void *)0)->a_Member) )
86#endif
87
88/** def KMK_CC_SIZEOF_MEMBER */
89#define KMK_CC_SIZEOF_MEMBER(a_Struct, a_Member) ( sizeof( ((a_Struct *)(void *)0x1000)->a_Member) )
90
91/** @def KMK_CC_SIZEOF_VAR_STRUCT
92 * Size of a struct with a variable sized array as the final member. */
93#define KMK_CC_SIZEOF_VAR_STRUCT(a_Struct, a_FinalArrayMember, a_cArray) \
94 ( KMK_CC_OFFSETOF(a_Struct, a_FinalArrayMember) + KMK_CC_SIZEOF_MEMBER(a_Struct, a_FinalArrayMember) * (a_cArray) )
95
96
97
98/** @def KMK_CC_STATIC_ASSERT_EX
99 * Compile time assertion with text.
100 */
101#ifdef _MSC_VER_
102# if _MSC_VER >= 1600
103# define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) static_assert(a_Expr, a_szExpl)
104# else
105# define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) typedef int RTASSERTVAR[(a_Expr) ? 1 : 0]
106# endif
107#elif defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__)
108# define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) static_assert(a_Expr, a_szExpl)
109#elif !defined(__GNUC__) && !defined(__IBMC__) && !defined(__IBMCPP__)
110# define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) typedef int KMK_CC_STATIC_ASSERT_EX_TYPE[(a_Expr) ? 1 : 0]
111#else
112# define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) extern int KMK_CC_STATIC_ASSERT_EX_VAR[(a_Expr) ? 1 : 0]
113extern int KMK_CC_STATIC_ASSERT_EX_VAR[1];
114#endif
115/** @def KMK_CC_STATIC_ASSERT
116 * Compile time assertion, simple variant.
117 */
118#define KMK_CC_STATIC_ASSERT(a_Expr) KMK_CC_STATIC_ASSERT_EX(a_Expr, #a_Expr)
119
120
121/** @def KMK_CC_IS_SPACE_CH
122 * Checks if it's a space char. */
123#define KMK_CC_IS_SPACE_CH(a_ch) isspace((unsigned char)(a_ch))
124
125
126/** @defgroup grp_kmk_cc_evalprog Makefile Evaluation
127 * @{
128 */
129/** @name KMK_CC_EVAL_QUALIFIER_XXX - Variable qualifiers.
130 * @{ */
131#define KMK_CC_EVAL_QUALIFIER_LOCAL 1
132#define KMK_CC_EVAL_QUALIFIER_EXPORT 2
133#define KMK_CC_EVAL_QUALIFIER_OVERRIDE 4
134#define KMK_CC_EVAL_QUALIFIER_PRIVATE 8
135/** @} */
136
137/** Eval: Max nesting depth of makefile conditionals.
138 * Affects stack usage in kmk_cc_eval_compile_worker. */
139#define KMK_CC_EVAL_MAX_IF_DEPTH 32
140/** Eval: Maximum number of escaped end of line sequences to track.
141 * Affects stack usage in kmk_cc_eval_compile_worker, but not the actual
142 * number of consequtive escaped newlines in the input file/variable. */
143#define KMK_CC_EVAL_MAX_ESC_EOLS 2
144
145/** Minimum keyword length. */
146#define KMK_CC_EVAL_KEYWORD_MIN 2
147/** Maximum keyword length. */
148#define KMK_CC_EVAL_KEYWORD_MAX 16
149
150/** @name KMK_CC_EVAL_CH_XXX - flags found in g_abEvalCcChars.
151 * @{ */
152/** Normal character, nothing special. */
153#define KMK_CC_EVAL_CH_NORMAL UINT16_C(0)
154/** Blank character. */
155#define KMK_CC_EVAL_CH_BLANK UINT16_C(1)
156#define KMK_CC_EVAL_IS_BLANK(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_BLANK)
157/** Space character. */
158#define KMK_CC_EVAL_CH_SPACE UINT16_C(2)
159#define KMK_CC_EVAL_IS_SPACE(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_SPACE)
160/** Space character or potential EOL escape backslash. */
161#define KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH UINT16_C(4)
162#define KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH)
163/** Anything we need to take notice of when parsing something could be a
164 * variable name or a recipe.
165 * All space characters, backslash (EOL escape), variable expansion dollar,
166 * variable assignment operator chars, recipe colon and recipe percent. */
167#define KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE UINT16_C(8)
168#define KMK_CC_EVAL_IS_SPACE_OR_VAR_OR_RECIPE(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE)
169/** Possible EOL character. */
170#define KMK_CC_EVAL_CH_EOL_CANDIDATE UINT16_C(16)
171#define KMK_CC_EVAL_IS_EOL_CANDIDATE(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_EOL_CANDIDATE)
172/** First character in a keyword. */
173#define KMK_CC_EVAL_CH_1ST_IN_KEYWORD UINT16_C(32)
174#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)
175/** Second character in a keyword. */
176#define KMK_CC_EVAL_CH_2ND_IN_KEYWORD UINT16_C(64)
177#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)
178/** First character in a variable qualifier keyword or 'define'. */
179#define KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD UINT16_C(128)
180#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)
181/** Used when parsing variable names, looking for the end of a nested
182 * variable reference. Matches parentheses and backslash (escaped eol). */
183#define KMK_CC_EVAL_CH_PAREN_OR_SLASH UINT16_C(256)
184#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)
185/** @} */
186
187/** Sets a bitmap entry.
188 * @param a_abBitmap Typically g_abEvalCcChars.
189 * @param a_ch The character to set.
190 * @param a_uVal The value to OR in. */
191#define KMK_CC_EVAL_BM_OR(g_abBitmap, a_ch, a_uVal) do { (g_abBitmap)[(unsigned char)(a_ch)] |= (a_uVal); } while (0)
192
193/** Gets a bitmap entry.
194 * @returns The value corresponding to @a a_ch.
195 * @param a_abBitmap Typically g_abEvalCcChars.
196 * @param a_ch The character to set. */
197#define KMK_CC_EVAL_BM_GET(g_abBitmap, a_ch) ( (g_abBitmap)[(unsigned char)(a_ch)] )
198
199/** @} */
200
201
202/*********************************************************************************************************************************
203* Structures and Typedefs *
204*********************************************************************************************************************************/
205/**
206 * Block of expand instructions.
207 *
208 * To avoid wasting space on "next" pointers, as well as a lot of time walking
209 * these chains when destroying programs, we work with blocks of instructions.
210 */
211typedef struct kmk_cc_block
212{
213 /** The pointer to the next block (LIFO). */
214 struct kmk_cc_block *pNext;
215 /** The size of this block. */
216 uint32_t cbBlock;
217 /** The offset of the next free byte in the block. When set to cbBlock the
218 * block is 100% full. */
219 uint32_t offNext;
220} KMKCCBLOCK;
221typedef KMKCCBLOCK *PKMKCCBLOCK;
222
223
224/** @defgroup grp_kmk_cc_exp String Expansion
225 * @{*/
226
227/**
228 * String expansion statistics.
229 */
230typedef struct KMKCCEXPSTATS
231{
232 /** Recent average size. */
233 uint32_t cchAvg;
234} KMKCCEXPSTATS;
235typedef KMKCCEXPSTATS *PKMKCCEXPSTATS;
236
237/**
238 * Expansion instructions.
239 */
240typedef enum KMKCCEXPINSTR
241{
242 /** Copy a plain string. */
243 kKmkCcExpInstr_CopyString = 0,
244 /** Insert an expanded variable value, which name we already know. */
245 kKmkCcExpInstr_PlainVariable,
246 /** Insert an expanded variable value, the name is dynamic (sub prog). */
247 kKmkCcExpInstr_DynamicVariable,
248 /** Insert an expanded variable value, which name we already know, doing
249 * search an replace on a string. */
250 kKmkCcExpInstr_SearchAndReplacePlainVariable,
251 /** Insert the output of function that requires no argument expansion. */
252 kKmkCcExpInstr_PlainFunction,
253 /** Insert the output of function that requires dynamic expansion of one ore
254 * more arguments. (Dynamic is perhaps not such a great name, but whatever.) */
255 kKmkCcExpInstr_DynamicFunction,
256 /** Jump to a new instruction block. */
257 kKmkCcExpInstr_Jump,
258 /** We're done, return. Has no specific structure. */
259 kKmkCcExpInstr_Return,
260 /** The end of valid instructions (exclusive). */
261 kKmkCcExpInstr_End
262} KMKCCEXPINSTR;
263
264/** Instruction core. */
265typedef struct kmk_cc_exp_core
266{
267 /** The instruction opcode number (KMKCCEXPINSTR). */
268 KMKCCEXPINSTR enmOpCode;
269} KMKCCEXPCORE;
270typedef KMKCCEXPCORE *PKMKCCEXPCORE;
271
272/**
273 * String expansion subprogram.
274 */
275#pragma pack(1) /* save some precious bytes */
276typedef struct kmk_cc_exp_subprog
277{
278 /** Pointer to the first instruction. */
279 PKMKCCEXPCORE pFirstInstr;
280 /** Statistics. */
281 KMKCCEXPSTATS Stats;
282} KMKCCEXPSUBPROG;
283#pragma pack()
284typedef KMKCCEXPSUBPROG *PKMKCCEXPSUBPROG;
285KMK_CC_STATIC_ASSERT(sizeof(KMKCCEXPSUBPROG) == 12 || sizeof(void *) != 8);
286
287
288/**
289 * String expansion subprogram or plain string.
290 */
291#pragma pack(1) /* save some precious bytes */
292typedef struct kmk_cc_exp_subprog_or_string
293{
294 /** Either a plain string pointer or a subprogram. */
295 union
296 {
297 /** Subprogram for expanding this argument. */
298 KMKCCEXPSUBPROG Subprog;
299 /** Pointer to the plain string. */
300 struct
301 {
302 /** Pointer to the string. */
303 const char *psz;
304 /** String length. */
305 uint32_t cch;
306 } Plain;
307 } u;
308 /** Set if subprogram (u.Subprog), clear if plain string (u.Plain). */
309 uint8_t fSubprog;
310 /** Set if the plain string is kept in the variable_strcache.
311 * @remarks Here rather than in u.Plain to make use of alignment padding. */
312 uint8_t fPlainIsInVarStrCache;
313 /** Context/user specific. */
314 uint8_t bUser;
315 /** Context/user specific #2. */
316 uint8_t bUser2;
317} KMKCCEXPSUBPROGORPLAIN;
318#pragma pack()
319typedef KMKCCEXPSUBPROGORPLAIN *PKMKCCEXPSUBPROGORPLAIN;
320KMK_CC_STATIC_ASSERT( sizeof(void *) == 8
321 ? sizeof(KMKCCEXPSUBPROGORPLAIN) == 16
322 : sizeof(void *) == 4
323 ? sizeof(KMKCCEXPSUBPROGORPLAIN) == 12
324 : 1);
325
326/**
327 * kKmkCcExpInstr_CopyString instruction format.
328 */
329typedef struct kmk_cc_exp_copy_string
330{
331 /** The core instruction. */
332 KMKCCEXPCORE Core;
333 /** The number of bytes to copy. */
334 uint32_t cchCopy;
335 /** Pointer to the source string (not terminated at cchCopy). */
336 const char *pachSrc;
337} KMKCCEXPCOPYSTRING;
338typedef KMKCCEXPCOPYSTRING *PKMKCCEXPCOPYSTRING;
339
340/**
341 * kKmkCcExpInstr_PlainVariable instruction format.
342 */
343typedef struct kmk_cc_exp_plain_variable
344{
345 /** The core instruction. */
346 KMKCCEXPCORE Core;
347 /** The name of the variable (points into variable_strcache). */
348 const char *pszName;
349} KMKCCEXPPLAINVAR;
350typedef KMKCCEXPPLAINVAR *PKMKCCEXPPLAINVAR;
351
352/**
353 * kKmkCcExpInstr_DynamicVariable instruction format.
354 */
355typedef struct kmk_cc_exp_dynamic_variable
356{
357 /** The core instruction. */
358 KMKCCEXPCORE Core;
359 /** The subprogram that will give us the variable name. */
360 KMKCCEXPSUBPROG Subprog;
361 /** Where to continue after this instruction. (This is necessary since the
362 * instructions of the subprogram are emitted after this instruction.) */
363 PKMKCCEXPCORE pNext;
364} KMKCCEXPDYNVAR;
365typedef KMKCCEXPDYNVAR *PKMKCCEXPDYNVAR;
366
367/**
368 * kKmkCcExpInstr_SearchAndReplacePlainVariable instruction format.
369 */
370typedef struct kmk_cc_exp_sr_plain_variable
371{
372 /** The core instruction. */
373 KMKCCEXPCORE Core;
374 /** Where to continue after this instruction. (This is necessary since the
375 * instruction contains string data of variable size.) */
376 PKMKCCEXPCORE pNext;
377 /** The name of the variable (points into variable_strcache). */
378 const char *pszName;
379 /** Search pattern. */
380 const char *pszSearchPattern;
381 /** Replacement pattern. */
382 const char *pszReplacePattern;
383 /** Offset into pszSearchPattern of the significant '%' char. */
384 uint32_t offPctSearchPattern;
385 /** Offset into pszReplacePattern of the significant '%' char. */
386 uint32_t offPctReplacePattern;
387} KMKCCEXPSRPLAINVAR;
388typedef KMKCCEXPSRPLAINVAR *PKMKCCEXPSRPLAINVAR;
389
390/**
391 * Instruction format parts common to both kKmkCcExpInstr_PlainFunction and
392 * kKmkCcExpInstr_DynamicFunction.
393 */
394typedef struct kmk_cc_exp_function_core
395{
396 /** The core instruction. */
397 KMKCCEXPCORE Core;
398 /** Number of arguments. */
399 uint32_t cArgs; /**< @todo uint16_t to save 7 bytes of unecessary alignment padding on 64-bit systems, or merge fDirty into this member. */
400 /** Set if the function could be modifying the input arguments. */
401 uint8_t fDirty;
402 /** Where to continue after this instruction. (This is necessary since the
403 * instructions are of variable size and may be followed by string data.) */
404 PKMKCCEXPCORE pNext;
405 /**
406 * Pointer to the function table entry.
407 *
408 * @returns New variable buffer position.
409 * @param pchDst Current variable buffer position.
410 * @param papszArgs Pointer to a NULL terminated array of argument strings.
411 * @param pszFuncName The name of the function being called.
412 */
413 char * (*pfnFunction)(char *pchDst, char **papszArgs, const char *pszFuncName);
414 /** Pointer to the function name in the variable string cache. */
415 const char *pszFuncName;
416} KMKCCEXPFUNCCORE;
417typedef KMKCCEXPFUNCCORE *PKMKCCEXPFUNCCORE;
418
419/**
420 * Instruction format for kKmkCcExpInstr_PlainFunction.
421 */
422typedef struct kmk_cc_exp_plain_function
423{
424 /** The bits comment to both plain and dynamic functions. */
425 KMKCCEXPFUNCCORE FnCore;
426 /** Variable sized argument list (cArgs + 1 in length, last entry is NULL).
427 * The string pointers are to memory following this instruction, to memory in
428 * the next block or to memory in the variable / makefile we're working on
429 * (if zero terminated appropriately). */
430 const char *apszArgs[1];
431} KMKCCEXPPLAINFUNC;
432typedef KMKCCEXPPLAINFUNC *PKMKCCEXPPLAINFUNC;
433/** Calculates the size of an KMKCCEXPPLAINFUNC structure with the apszArgs
434 * member holding a_cArgs entries plus a NULL terminator. */
435#define KMKCCEXPPLAINFUNC_SIZE(a_cArgs) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEXPDYNFUNC, aArgs, (a_cArgs) + 1)
436
437/**
438 * Instruction format for kKmkCcExpInstr_DynamicFunction.
439 */
440typedef struct kmk_cc_exp_dyn_function
441{
442 /** The bits comment to both plain and dynamic functions. */
443 KMKCCEXPFUNCCORE FnCore;
444 /** Variable sized argument list (FnCore.cArgs in length).
445 * The subprograms / strings are allocated after this array (or in the next
446 * block). */
447 KMKCCEXPSUBPROGORPLAIN aArgs[1];
448} KMKCCEXPDYNFUNC;
449typedef KMKCCEXPDYNFUNC *PKMKCCEXPDYNFUNC;
450/** Calculates the size of an KMKCCEXPDYNFUNC structure with the apszArgs
451 * member holding a_cArgs entries (no zero terminator). */
452#define KMKCCEXPDYNFUNC_SIZE(a_cArgs) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEXPDYNFUNC, aArgs, a_cArgs)
453
454/**
455 * Instruction format for kKmkCcExpInstr_Jump.
456 */
457typedef struct kmk_cc_exp_jump
458{
459 /** The core instruction. */
460 KMKCCEXPCORE Core;
461 /** Where to jump to (new instruction block, typically). */
462 PKMKCCEXPCORE pNext;
463} KMKCCEXPJUMP;
464typedef KMKCCEXPJUMP *PKMKCCEXPJUMP;
465
466/**
467 * String expansion program.
468 */
469typedef struct kmk_cc_expandprog
470{
471 /** Pointer to the first instruction for this program. */
472 PKMKCCEXPCORE pFirstInstr;
473 /** List of blocks for this program (LIFO). */
474 PKMKCCBLOCK pBlockTail;
475 /** Statistics. */
476 KMKCCEXPSTATS Stats;
477#ifdef KMK_CC_STRICT
478 /** The hash of the input string. Used to check that we get all the change
479 * notifications we require. */
480 uint32_t uInputHash;
481#endif
482 /** Reference count. */
483 uint32_t volatile cRefs;
484} KMKCCEXPPROG;
485/** Pointer to a string expansion program. */
486typedef KMKCCEXPPROG *PKMKCCEXPPROG;
487
488/** @} */
489
490
491/** @addtogroup grp_kmk_cc_evalprog
492 * @{ */
493
494/** Pointer to a makefile evaluation program. */
495typedef struct kmk_cc_evalprog *PKMKCCEVALPROG;
496
497/**
498 * Makefile evaluation instructions.
499 */
500typedef enum KMKCCEVALINSTR
501{
502 /** Jump instruction - KMKCCEVALJUMP. */
503 kKmkCcEvalInstr_jump = 0,
504
505 /** [local|override|export] variable = value - KMKCCEVALASSIGN.
506 * @note Can be used for target-specific variables. */
507 kKmkCcEvalInstr_assign_recursive,
508 /** [local|override|export] variable := value - KMKCCEVALASSIGN.
509 * @note Can be used for target-specific variables. */
510 kKmkCcEvalInstr_assign_simple,
511 /** [local|override|export] variable += value - KMKCCEVALASSIGN.
512 * @note Can be used for target-specific variables. */
513 kKmkCcEvalInstr_assign_append,
514 /** [local|override|export] variable -= value - KMKCCEVALASSIGN.
515 * @note Can be used for target-specific variables. */
516 kKmkCcEvalInstr_assign_prepend,
517 /** [local|override|export] variable ?= value - KMKCCEVALASSIGN.
518 * @note Can be used for target-specific variables. */
519 kKmkCcEvalInstr_assign_if_new,
520 /** [local|override|export] define variable ... endef - KMKCCEVALASSIGNDEF. */
521 kKmkCcEvalInstr_assign_define,
522
523 /** export variable1 [variable2...] - KMKCCEVALEXPORT. */
524 kKmkCcEvalInstr_export,
525 /** unexport variable1 [variable2...] - KMKCCEVALEXPORT. */
526 kKmkCcEvalInstr_unexport,
527 /** export - KMKCCEVALCORE. */
528 kKmkCcEvalInstr_export_all,
529 /** unexport - KMKCCEVALCORE. */
530 kKmkCcEvalInstr_unexport_all,
531
532 /** [else] ifdef variable - KMKCCEVALIFDEFPLAIN. */
533 kKmkCcEvalInstr_ifdef_plain,
534 /** [else] ifndef variable - KMKCCEVALIFDEFPLAIN. */
535 kKmkCcEvalInstr_ifndef_plain,
536 /** [else] ifdef variable - KMKCCEVALIFDEFDYNAMIC. */
537 kKmkCcEvalInstr_ifdef_dynamic,
538 /** [else] ifndef variable - KMKCCEVALIFDEFDYNAMIC. */
539 kKmkCcEvalInstr_ifndef_dynamic,
540 /** [else] ifeq (a,b) - KMKCCEVALIFEQ. */
541 kKmkCcEvalInstr_ifeq,
542 /** [else] ifeq (a,b) - KMKCCEVALIFEQ. */
543 kKmkCcEvalInstr_ifneq,
544 /** [else] if1of (set-a,set-b) - KMKCCEVALIF1OF. */
545 kKmkCcEvalInstr_if1of,
546 /** [else] ifn1of (set-a,set-b) - KMKCCEVALIF1OF. */
547 kKmkCcEvalInstr_ifn1of,
548 /** [else] if expr - KMKCCEVALIFEXPR. */
549 kKmkCcEvalInstr_if,
550
551 /** include file1 [file2...] - KMKCCEVALINCLUDE. */
552 kKmkCcEvalInstr_include,
553 /** [sinclude|-include] file1 [file2...] - KMKCCEVALINCLUDE. */
554 kKmkCcEvalInstr_include_silent,
555 /** includedep file1 [file2...] - KMKCCEVALINCLUDE. */
556 kKmkCcEvalInstr_includedep,
557 /** includedep-queue file1 [file2...] - KMKCCEVALINCLUDE. */
558 kKmkCcEvalInstr_includedep_queue,
559 /** includedep-flush file1 [file2...] - KMKCCEVALINCLUDE. */
560 kKmkCcEvalInstr_includedep_flush,
561
562 /** Recipe without commands (defines dependencies) - KMKCCEVALRECIPE. */
563 kKmkCcEvalInstr_recipe_no_commands,
564 /** Recipe with commands (defines dependencies) - KMKCCEVALRECIPE. */
565 kKmkCcEvalInstr_recipe_start_normal,
566 /** Recipe with commands (defines dependencies) - KMKCCEVALRECIPE. */
567 kKmkCcEvalInstr_recipe_start_double_colon,
568 /** Recipe with commands (defines dependencies) - KMKCCEVALRECIPE. */
569 kKmkCcEvalInstr_recipe_start_pattern,
570 /** Adds more commands to the current recipe - KMKCCEVALRECIPECOMMANDS. */
571 kKmkCcEvalInstr_recipe_commands,
572 /** Special instruction for indicating the end of the recipe commands - KMKCCEVALCORE. */
573 kKmkCcEvalInstr_recipe_end,
574 /** Cancel previously defined pattern rule - KMKCCEVALRECIPE. */
575 kKmkCcEvalInstr_recipe_cancel_pattern,
576
577 /** vpath pattern directories - KMKCCEVALVPATH. */
578 kKmkCcEvalInstr_vpath,
579 /** vpath pattern directories - KMKCCEVALVPATH. */
580 kKmkCcEvalInstr_vpath_clear_pattern,
581 /** vpath - KMKCCEVALCORE. */
582 kKmkCcEvalInstr_vpath_clear_all,
583
584 /** The end of valid instructions (exclusive). */
585 kKmkCcEvalInstr_End
586} KMKCCEVALINSTR;
587
588/**
589 * Instruction core common to all instructions.
590 */
591typedef struct kmk_cc_eval_core
592{
593 /** The instruction opcode number (KMKCCEVALINSTR). */
594 KMKCCEVALINSTR enmOpCode;
595 /** The line number in the source this statement is associated with. */
596 unsigned iLine;
597} KMKCCEVALCORE;
598/** Pointer to an instruction core structure. */
599typedef KMKCCEVALCORE *PKMKCCEVALCORE;
600
601/**
602 * Instruction format for kKmkCcEvalInstr_jump.
603 */
604typedef struct kmk_cc_eval_jump
605{
606 /** The core instruction. */
607 KMKCCEVALCORE Core;
608 /** Where to jump to (new instruction block or endif, typically). */
609 PKMKCCEVALCORE pNext;
610} KMKCCEVALJUMP;
611typedef KMKCCEVALJUMP *PKMKCCEVALJUMP;
612
613/**
614 * Instruction format for kKmkCcEvalInstr_assign_recursive,
615 * kKmkCcEvalInstr_assign_simple, kKmkCcEvalInstr_assign_append,
616 * kKmkCcEvalInstr_assign_prepend and kKmkCcEvalInstr_assign_if_new.
617 */
618typedef struct kmk_cc_eval_assign
619{
620 /** The core instruction. */
621 KMKCCEVALCORE Core;
622 /** Whether the 'export' directive was used. */
623 uint8_t fExport;
624 /** Whether the 'override' directive was used. */
625 uint8_t fOverride;
626 /** Whether the 'local' directive was used. */
627 uint8_t fLocal;
628 /** The variable name.
629 * @remarks Plain text names are in variable_strcache. */
630 KMKCCEXPSUBPROGORPLAIN Variable;
631 /** The value or value expression. */
632 KMKCCEXPSUBPROGORPLAIN Value;
633 /** Pointer to the next instruction. */
634 PKMKCCEVALCORE pNext;
635} KMKCCEVALASSIGN;
636typedef KMKCCEVALASSIGN *PKMKCCEVALASSIGN;
637
638/**
639 * Instruction format for kKmkCcEvalInstr_assign_define.
640 */
641typedef struct kmk_cc_eval_assign_define
642{
643 /** The assignment core structure. */
644 KMKCCEVALASSIGN AssignCore;
645 /** Makefile evaluation program compiled from the define.
646 * NULL if it does not compile.
647 * @todo Let's see if this is actually doable... */
648 PKMKCCEVALPROG pEvalProg;
649} KMKCCEVALASSIGNDEF;
650typedef KMKCCEVALASSIGNDEF *PKMKCCEVALASSIGNDEF;
651
652/**
653 * Instruction format for kKmkCcEvalInstr_export and kKmkCcEvalInstr_unexport.
654 */
655typedef struct kmk_cc_eval_export
656{
657 /** The core instruction. */
658 KMKCCEVALCORE Core;
659 /** The number of variables named in aVars. */
660 uint32_t cVars;
661 /** Pointer to the next instruction. */
662 PKMKCCEVALCORE pNext;
663 /** The variable names.
664 * Expressions will be expanded and split on space.
665 * @remarks Plain text names are in variable_strcache. */
666 KMKCCEXPSUBPROGORPLAIN aVars[1];
667} KMKCCEVALEXPORT;
668typedef KMKCCEVALEXPORT *PKMKCCEVALEXPORT;
669/** Calculates the size of an KMKCCEVALEXPORT structure for @a a_cVars. */
670#define KMKCCEVALEXPORT_SIZE(a_cVars) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALVPATH, aVars, a_cVars)
671
672/**
673 * Core structure for all conditionals (kKmkCcEvalInstr_if*).
674 */
675typedef struct kmk_cc_eval_if_core
676{
677 /** The core instruction. */
678 KMKCCEVALCORE Core;
679 /** Condition true: Pointer to the next instruction. */
680 PKMKCCEVALCORE pNextTrue;
681 /** Condition false: Pointer to the next instruction (i.e. 'else if*'
682 * or whatever follows 'else' / 'endif'. */
683 PKMKCCEVALCORE pNextFalse;
684 /** Pointer to the previous conditional for 'else if*' directives.
685 * This is only to assist the compilation process. */
686 struct kmk_cc_eval_if_core *pPrevCond;
687 /** Pointer to the jump out of the true block, if followed by 'else'.
688 * This is only to assist the compilation process. */
689 PKMKCCEVALJUMP pTrueEndJump;
690} KMKCCEVALIFCORE;
691typedef KMKCCEVALIFCORE *PKMKCCEVALIFCORE;
692
693/**
694 * Instruction format for kKmkCcEvalInstr_ifdef_plain and
695 * kKmkCcEvalInstr_ifndef_plain.
696 * The variable name is known at compilation time.
697 */
698typedef struct kmk_cc_eval_ifdef_plain
699{
700 /** The 'if' core structure. */
701 KMKCCEVALIFCORE IfCore;
702 /** The name of the variable (points into variable_strcache). */
703 const char *pszName;
704} KMKCCEVALIFDEFPLAIN;
705typedef KMKCCEVALIFDEFPLAIN *PKMKCCEVALIFDEFPLAIN;
706
707/**
708 * Instruction format for kKmkCcEvalInstr_ifdef_dynamic and
709 * kKmkCcEvalInstr_ifndef_dynamic.
710 * The variable name is dynamically expanded at run time.
711 */
712typedef struct kmk_cc_eval_ifdef_dynamic
713{
714 /** The 'if' core structure. */
715 KMKCCEVALIFCORE IfCore;
716 /** The subprogram that will give us the variable name. */
717 KMKCCEXPSUBPROG NameSubprog;
718} KMKCCEVALIFDEFDYNAMIC;
719typedef KMKCCEVALIFDEFDYNAMIC *PKMKCCEVALIFDEFDYNAMIC;
720
721/**
722 * Instruction format for kKmkCcEvalInstr_ifeq and kKmkCcEvalInstr_ifneq.
723 */
724typedef struct kmk_cc_eval_ifeq
725{
726 /** The 'if' core structure. */
727 KMKCCEVALIFCORE IfCore;
728 /** The left hand side string expression (dynamic or plain). */
729 KMKCCEXPSUBPROGORPLAIN Left;
730 /** The rigth hand side string expression (dynamic or plain). */
731 KMKCCEXPSUBPROGORPLAIN Right;
732} KMKCCEVALIFEQ;
733typedef KMKCCEVALIFEQ *PKMKCCEVALIFEQ;
734
735/**
736 * Instruction format for kKmkCcEvalInstr_if1of and kKmkCcEvalInstr_ifn1of.
737 *
738 * @todo This can be optimized further by pre-hashing plain text items. One of
739 * the sides are usually plain text.
740 */
741typedef struct kmk_cc_eval_if1of
742{
743 /** The 'if' core structure. */
744 KMKCCEVALIFCORE IfCore;
745 /** The left hand side string expression (dynamic or plain). */
746 KMKCCEXPSUBPROGORPLAIN Left;
747 /** The rigth hand side string expression (dynamic or plain). */
748 KMKCCEXPSUBPROGORPLAIN Right;
749} KMKCCEVALIF1OF;
750typedef KMKCCEVALIF1OF *PKMKCCEVALIF1OF;
751
752/**
753 * Instruction format for kKmkCcEvalInstr_if.
754 *
755 * @todo Parse and compile the expression. At least strip whitespace in it.
756 */
757typedef struct kmk_cc_eval_if_expr
758{
759 /** The 'if' core structure. */
760 KMKCCEVALIFCORE IfCore;
761 /** The expression string length. */
762 uint16_t cchExpr;
763 /** The expression string. */
764 char szExpr[1];
765} KMKCCEVALIFEXPR;
766typedef KMKCCEVALIFEXPR *PKMKCCEVALIFEXPR;
767/** Calculates the size of an KMKCCEVALIFEXPR structure for @a a_cchExpr long
768 * expression string (terminator is automatically added). */
769#define KMKCCEVALIFEXPR_SIZE(a_cchExpr) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALIFEXPR, szExpr, (a_cchExpr) + 1)
770
771/**
772 * Instruction format for kKmkCcEvalInstr_include,
773 * kKmkCcEvalInstr_include_silent, kKmkCcEvalInstr_includedep,
774 * kKmkCcEvalInstr_includedep_queue, kKmkCcEvalInstr_includedep_flush.
775 */
776typedef struct kmk_cc_eval_include
777{
778 /** The core instruction. */
779 KMKCCEVALCORE Core;
780 /** The number of files. */
781 uint32_t cFiles;
782 /** Pointer to the next instruction (subprogs and strings after this one). */
783 PKMKCCEVALCORE pNext;
784 /** The files to be included.
785 * Expressions will be expanded and split on space.
786 * @todo Plain text file name could be replaced by file string cache entries. */
787 KMKCCEXPSUBPROGORPLAIN aFiles[1];
788} KMKCCEVALINCLUDE;
789typedef KMKCCEVALINCLUDE *PKMKCCEVALINCLUDE;
790/** Calculates the size of an KMKCCEVALINCLUDE structure for @a a_cFiles files. */
791#define KMKCCEVALINCLUDE_SIZE(a_cFiles) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALINCLUDE, aFiles, a_cFiles)
792
793/**
794 * Instruction format for kKmkCcEvalInstr_recipe_no_commands,
795 * kKmkCcEvalInstr_recipe_start_normal,
796 * kKmkCcEvalInstr_recipe_start_double_colon, kKmkCcEvalInstr_includedep_queue,
797 * kKmkCcEvalInstr_recipe_start_pattern.
798 */
799typedef struct kmk_cc_eval_recipe
800{
801 /** The core instruction. */
802 KMKCCEVALCORE Core;
803 /** The total number of files and dependencies in aFilesAndDeps. */
804 uint16_t cFilesAndDeps;
805
806 /** Number of targets (from index 0).
807 * This is always 1 if this is an explicit multitarget or pattern recipe,
808 * indicating the main target. */
809 uint16_t cTargets;
810 /** Explicit multitarget & patterns: First always made target. */
811 uint16_t iFirstAlwaysMadeTargets;
812 /** Explicit multitarget & patterns: Number of always targets. */
813 uint16_t cAlwaysMadeTargets;
814 /** Explicit multitarget: First maybe made target. */
815 uint16_t iFirstMaybeTarget;
816 /** Explicit multitarget: Number of maybe made targets. */
817 uint16_t cMaybeTargets;
818
819 /** First dependency. */
820 uint16_t iFirstDep;
821 /** Number of ordinary dependnecies. */
822 uint16_t cDeps;
823 /** First order only dependency. */
824 uint16_t iFirstOrderOnlyDep;
825 /** Number of ordinary dependnecies. */
826 uint16_t cOrderOnlyDeps;
827
828 /** Pointer to the next instruction (subprogs and strings after this one). */
829 PKMKCCEVALCORE pNext;
830 /** The .MUST_MAKE variable value, if present.
831 * If not present, this is a zero length plain string. */
832 KMKCCEXPSUBPROGORPLAIN MustMake;
833 /** The target files and dependencies.
834 * This is sorted into several sections, as defined by the above indexes and
835 * counts. Expressions will be expanded and split on space.
836 *
837 * The KMKCCEXPSUBPROGORPLAIN::bUser member one of KMKCCEVALRECIPE_FD_XXX.
838 *
839 * @todo Plain text file name could be replaced by file string cache entries. */
840 KMKCCEXPSUBPROGORPLAIN aFilesAndDeps[1];
841} KMKCCEVALRECIPE;
842typedef KMKCCEVALRECIPE *PKMKCCEVALRECIPE;
843/** Calculates the size of an KMKCCEVALRECIPE structure for @a a_cFiles
844 * files. */
845#define KMKCCEVALRECIPE_SIZE(a_cFilesAndDeps) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALRECIPE, aFilesAndDeps, a_cFilesAndDeps)
846/** @name KMKCCEVALRECIPE_FD_XXX - Values for KMKCCEVALRECIPE::aFilesAndDeps[x].bUser
847 * @{ */
848#define KMKCCEVALRECIPE_FD_NORMAL 0
849#define KMKCCEVALRECIPE_FD_SEC_EXP 1
850#define KMKCCEVALRECIPE_FD_SPECIAL_POSIX 2
851#define KMKCCEVALRECIPE_FD_SPECIAL_SECONDEXPANSION 3
852#define KMKCCEVALRECIPE_FD_SPECIAL_ONESHELL 4
853/** @} */
854
855
856/**
857 * Instruction format for kKmkCcEvalInstr_recipe_commands.
858 */
859typedef struct kmk_cc_eval_recipe_commands
860{
861 /** The core instruction. */
862 KMKCCEVALCORE Core;
863 /** The number of search directories. */
864 uint32_t cCommands;
865 /** Pointer to the next instruction (subprogs and strings after this one). */
866 PKMKCCEVALCORE pNext;
867 /** Commands to add to the current recipe.
868 * Expressions will be expanded and split on space. */
869 KMKCCEXPSUBPROGORPLAIN aCommands[1];
870} KMKCCEVALRECIPECOMMANDS;
871typedef KMKCCEVALRECIPECOMMANDS *PKMKCCEVALRECIPECOMMANDS;
872/** Calculates the size of an KMKCCEVALRECIPECOMMANDS structure for
873 * @a a_cCommands commands. */
874#define KMKCCEVALRECIPECOMMANDS_SIZE(a_cCommands) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALRECIPECOMMANDS, aCommands, a_cCommands)
875
876/**
877 * Instruction format for kKmkCcEvalInstr_vpath and
878 * kKmkCcEvalInstr_vpath_clear_pattern.
879 */
880typedef struct kmk_cc_eval_vpath
881{
882 /** The core instruction. */
883 KMKCCEVALCORE Core;
884 /** The number of search directories.
885 * This will be zero for kKmkCcEvalInstr_vpath_clear_pattern. */
886 uint32_t cDirs;
887 /** Pointer to the next instruction (subprogs and strings after this one). */
888 PKMKCCEVALCORE pNext;
889 /** The pattern. */
890 KMKCCEXPSUBPROGORPLAIN Pattern;
891 /** The directory. Expressions will be expanded and split on space. */
892 KMKCCEXPSUBPROGORPLAIN aDirs[1];
893} KMKCCEVALVPATH;
894typedef KMKCCEVALVPATH *PKMKCCEVALVPATH;
895/** Calculates the size of an KMKCCEVALVPATH structure for @a a_cFiles files. */
896#define KMKCCEVALVPATH_SIZE(a_cFiles) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALVPATH, aDirs, a_cDirs)
897
898
899/**
900 * Makefile evaluation program.
901 */
902typedef struct kmk_cc_evalprog
903{
904 /** Pointer to the first instruction for this program. */
905 PKMKCCEVALCORE pFirstInstr;
906 /** List of blocks for this program (LIFO). */
907 PKMKCCBLOCK pBlockTail;
908 /** The name of the file containing this program. */
909 const char *pszFilename;
910 /** The name of the variable containing this program, if applicable. */
911 const char *pszVarName;
912#ifdef KMK_CC_STRICT
913 /** The hash of the input string. Used to check that we get all the change
914 * notifications we require. */
915 uint32_t uInputHash;
916#endif
917 /** Reference count. */
918 uint32_t volatile cRefs;
919} KMKCCEVALPROG;
920typedef KMKCCEVALPROG *PKMKCCEVALPROG;
921
922/** @} */
923
924
925/*********************************************************************************************************************************
926* Global Variables *
927*********************************************************************************************************************************/
928static uint32_t g_cVarForExpandCompilations = 0;
929static uint32_t g_cVarForExpandExecs = 0;
930static uint32_t g_cVarForEvalCompilations = 0;
931static uint32_t g_cVarForEvalExecs = 0;
932static uint32_t g_cFileForEvalCompilations = 0;
933static uint32_t g_cFileForEvalExecs = 0;
934#ifdef KMK_CC_WITH_STATS
935static uint32_t g_cBlockAllocated = 0;
936static uint32_t g_cbAllocated = 0;
937
938static uint32_t g_cBlocksAllocatedExpProgs = 0;
939static uint32_t g_cbAllocatedExpProgs = 0;
940static uint32_t g_cSingleBlockExpProgs = 0;
941static uint32_t g_cTwoBlockExpProgs = 0;
942static uint32_t g_cMultiBlockExpProgs = 0;
943static uint32_t g_cbUnusedMemExpProgs = 0;
944
945static uint32_t g_cBlocksAllocatedEvalProgs = 0;
946static uint32_t g_cbAllocatedEvalProgs = 0;
947static uint32_t g_cSingleBlockEvalProgs = 0;
948static uint32_t g_cTwoBlockEvalProgs = 0;
949static uint32_t g_cMultiBlockEvalProgs = 0;
950static uint32_t g_cbUnusedMemEvalProgs = 0;
951
952#endif
953
954/** Generic character classification, taking an 'unsigned char' index.
955 * ASSUMES unsigned char is 8-bits. */
956static uint16_t g_abEvalCcChars[256];
957
958
959/**
960 * Makefile evaluation keywords.
961 */
962static const char * const g_apszEvalKeywords[] =
963{
964 "define",
965 "export",
966 "else",
967 "endef",
968 "endif",
969 "ifdef",
970 "ifndef",
971 "ifeq",
972 "ifneq",
973 "if1of",
974 "ifn1of",
975 "if",
976 "include",
977 "includedep",
978 "includedep-queue",
979 "includedep-flush",
980 "local",
981 "override",
982 "private",
983 "sinclude",
984 "unexport",
985 "undefine",
986 "vpath",
987 "-include",
988};
989
990
991/*********************************************************************************************************************************
992* Internal Functions *
993*********************************************************************************************************************************/
994static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubprog);
995static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubprog, uint32_t *pcch);
996
997
998/**
999 * Initializes global variables for the 'compiler'.
1000 */
1001void kmk_cc_init(void)
1002{
1003 unsigned i;
1004
1005 /*
1006 * Initialize the bitmap.
1007 */
1008 memset(g_abEvalCcChars, 0, sizeof(g_abEvalCcChars));
1009
1010 /* blank chars */
1011 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ' ', KMK_CC_EVAL_CH_BLANK);
1012 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\t', KMK_CC_EVAL_CH_BLANK);
1013
1014 /* space chars and zero terminator. */
1015#define MY_SPACE_BITS KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE
1016 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ' ', MY_SPACE_BITS);
1017 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\t', MY_SPACE_BITS);
1018 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\n', MY_SPACE_BITS | KMK_CC_EVAL_CH_EOL_CANDIDATE);
1019 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\v', MY_SPACE_BITS);
1020 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\f', MY_SPACE_BITS);
1021 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\r', MY_SPACE_BITS | KMK_CC_EVAL_CH_EOL_CANDIDATE);
1022 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
1023#undef MY_SPACE_BITS
1024
1025 /* keywords */
1026 for (i = 0; i < K_ELEMENTS(g_apszEvalKeywords); i++)
1027 {
1028 size_t cch = strlen(g_apszEvalKeywords[i]);
1029 KMK_CC_ASSERT(cch >= KMK_CC_EVAL_KEYWORD_MIN);
1030 KMK_CC_ASSERT(cch <= KMK_CC_EVAL_KEYWORD_MAX);
1031
1032 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, g_apszEvalKeywords[i][0], KMK_CC_EVAL_CH_1ST_IN_KEYWORD);
1033 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, g_apszEvalKeywords[i][1], KMK_CC_EVAL_CH_2ND_IN_KEYWORD);
1034 }
1035 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'd', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* define */
1036 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'e', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* export (, endef) */
1037 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'l', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* local */
1038 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'o', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* override */
1039 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'p', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* private */
1040 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'u', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* undefine */
1041
1042 /* Assignment punctuation and recipe stuff. */
1043 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '=', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
1044 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ':', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
1045 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '<', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
1046 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '?', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
1047 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '+', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
1048 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '%', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE); /* uncertain... */
1049
1050 /* For locating the end of variable expansion. */
1051 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '(', KMK_CC_EVAL_CH_PAREN_OR_SLASH);
1052 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ')', KMK_CC_EVAL_CH_PAREN_OR_SLASH);
1053 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '{', KMK_CC_EVAL_CH_PAREN_OR_SLASH);
1054 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '}', KMK_CC_EVAL_CH_PAREN_OR_SLASH);
1055 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_PAREN_OR_SLASH);
1056}
1057
1058
1059/**
1060 * Prints stats (for kmk -p).
1061 */
1062void kmk_cc_print_stats(void)
1063{
1064#ifdef KMK_CC_WITH_STATS
1065 uint32_t const cEvalCompilations = g_cFileForEvalCompilations + g_cVarForEvalCompilations;
1066#endif
1067
1068 puts(_("\n# The kmk 'compiler' and kmk 'program executor':\n"));
1069
1070 printf(_("# Variables compiled for string expansion: %6u\n"), g_cVarForExpandCompilations);
1071 printf(_("# Variables string expansion runs: %6u\n"), g_cVarForExpandExecs);
1072 printf(_("# String expansion runs per compile: %6u\n"), g_cVarForExpandExecs / g_cVarForExpandCompilations);
1073#ifdef KMK_CC_WITH_STATS
1074 printf(_("# Single alloc block exp progs: %6u (%u%%)\n"
1075 "# Two alloc block exp progs: %6u (%u%%)\n"
1076 "# Three or more alloc block exp progs: %6u (%u%%)\n"
1077 ),
1078 g_cSingleBlockExpProgs, (uint32_t)((uint64_t)g_cSingleBlockExpProgs * 100 / g_cVarForExpandCompilations),
1079 g_cTwoBlockExpProgs, (uint32_t)((uint64_t)g_cTwoBlockExpProgs * 100 / g_cVarForExpandCompilations),
1080 g_cMultiBlockExpProgs, (uint32_t)((uint64_t)g_cMultiBlockExpProgs * 100 / g_cVarForExpandCompilations));
1081 printf(_("# Total amount of memory for exp progs: %8u bytes\n"
1082 "# in: %6u blocks\n"
1083 "# avg block size: %6u bytes\n"
1084 "# unused memory: %8u bytes (%u%%)\n"
1085 "# avg unused memory per block: %6u bytes\n"
1086 "\n"),
1087 g_cbAllocatedExpProgs, g_cBlocksAllocatedExpProgs, g_cbAllocatedExpProgs / g_cBlocksAllocatedExpProgs,
1088 g_cbUnusedMemExpProgs, (uint32_t)((uint64_t)g_cbUnusedMemExpProgs * 100 / g_cbAllocatedExpProgs),
1089 g_cbUnusedMemExpProgs / g_cBlocksAllocatedExpProgs);
1090 puts("");
1091#endif
1092 printf(_("# Variables compiled for string eval: %6u\n"), g_cVarForEvalCompilations);
1093 printf(_("# Variables string eval runs: %6u\n"), g_cVarForEvalExecs);
1094 printf(_("# String evals runs per compile: %6u\n"), g_cVarForEvalExecs / g_cVarForEvalCompilations);
1095 printf(_("# Files compiled: %6u\n"), g_cFileForEvalCompilations);
1096 printf(_("# Files runs: %6u\n"), g_cFileForEvalExecs);
1097 printf(_("# Files eval runs per compile: %6u\n"), g_cFileForEvalExecs / g_cFileForEvalCompilations);
1098#ifdef KMK_CC_WITH_STATS
1099 printf(_("# Single alloc block eval progs: %6u (%u%%)\n"
1100 "# Two alloc block eval progs: %6u (%u%%)\n"
1101 "# Three or more alloc block eval progs: %6u (%u%%)\n"
1102 ),
1103 g_cSingleBlockEvalProgs, (uint32_t)((uint64_t)g_cSingleBlockEvalProgs * 100 / cEvalCompilations),
1104 g_cTwoBlockEvalProgs, (uint32_t)((uint64_t)g_cTwoBlockEvalProgs * 100 / cEvalCompilations),
1105 g_cMultiBlockEvalProgs, (uint32_t)((uint64_t)g_cMultiBlockEvalProgs * 100 / cEvalCompilations));
1106 printf(_("# Total amount of memory for eval progs: %8u bytes\n"
1107 "# in: %6u blocks\n"
1108 "# avg block size: %6u bytes\n"
1109 "# unused memory: %8u bytes (%u%%)\n"
1110 "# avg unused memory per block: %6u bytes\n"
1111 "\n"),
1112 g_cbAllocatedEvalProgs, g_cBlocksAllocatedEvalProgs, g_cbAllocatedEvalProgs / g_cBlocksAllocatedEvalProgs,
1113 g_cbUnusedMemEvalProgs, (uint32_t)((uint64_t)g_cbUnusedMemEvalProgs * 100 / g_cbAllocatedEvalProgs),
1114 g_cbUnusedMemEvalProgs / g_cBlocksAllocatedEvalProgs);
1115 puts("");
1116 printf(_("# Total amount of block mem allocated: %8u bytes\n"), g_cbAllocated);
1117 printf(_("# Total number of block allocated: %8u\n"), g_cBlockAllocated);
1118 printf(_("# Average block size: %8u byte\n"), g_cbAllocated / g_cBlockAllocated);
1119#endif
1120
1121 puts("");
1122}
1123
1124
1125/*
1126 *
1127 * Various utility functions.
1128 * Various utility functions.
1129 * Various utility functions.
1130 *
1131 */
1132
1133/**
1134 * Counts the number of dollar chars in the string.
1135 *
1136 * @returns Number of dollar chars.
1137 * @param pchStr The string to search (does not need to be zero
1138 * terminated).
1139 * @param cchStr The length of the string.
1140 */
1141static uint32_t kmk_cc_count_dollars(const char *pchStr, uint32_t cchStr)
1142{
1143 uint32_t cDollars = 0;
1144 const char *pch;
1145 while ((pch = memchr(pchStr, '$', cchStr)) != NULL)
1146 {
1147 cDollars++;
1148 cchStr -= pch - pchStr + 1;
1149 pchStr = pch + 1;
1150 }
1151 return cDollars;
1152}
1153
1154#ifdef KMK_CC_STRICT
1155/**
1156 * Used to check that function arguments are left alone.
1157 * @returns Updated hash.
1158 * @param uHash The current hash value.
1159 * @param psz The string to hash.
1160 */
1161static uint32_t kmk_cc_debug_string_hash(uint32_t uHash, const char *psz)
1162{
1163 unsigned char ch;
1164 while ((ch = *(unsigned char const *)psz++) != '\0')
1165 uHash = (uHash << 6) + (uHash << 16) - uHash + (unsigned char)ch;
1166 return uHash;
1167}
1168
1169/**
1170 * Used to check that function arguments are left alone.
1171 * @returns Updated hash.
1172 * @param uHash The current hash value.
1173 * @param pch The string to hash, not terminated.
1174 * @param cch The number of chars to hash.
1175 */
1176static uint32_t kmk_cc_debug_string_hash_n(uint32_t uHash, const char *pch, uint32_t cch)
1177{
1178 while (cch-- > 0)
1179 {
1180 unsigned char ch = *(unsigned char const *)pch++;
1181 uHash = (uHash << 6) + (uHash << 16) - uHash + (unsigned char)ch;
1182 }
1183 return uHash;
1184}
1185
1186#endif
1187
1188
1189
1190/*
1191 *
1192 * The allocator.
1193 * The allocator.
1194 * The allocator.
1195 *
1196 */
1197
1198
1199/**
1200 * For the first allocation using the block allocator.
1201 *
1202 * @returns Pointer to the first allocation (@a cbFirst in size).
1203 * @param ppBlockTail Where to return the pointer to the first block.
1204 * @param cbFirst The size of the first allocation.
1205 * @param cbHint Hint about how much memory we might be needing.
1206 */
1207static void *kmk_cc_block_alloc_first(PKMKCCBLOCK *ppBlockTail, size_t cbFirst, size_t cbHint)
1208{
1209 uint32_t cbBlock;
1210 PKMKCCBLOCK pNewBlock;
1211
1212 KMK_CC_ASSERT_ALIGNED(cbFirst, sizeof(void *));
1213 KMK_CC_ASSERT(cbFirst <= 128);
1214
1215 /*
1216 * Turn the hint into a block size.
1217 */
1218 cbHint += cbFirst;
1219 if (cbHint <= 512)
1220 {
1221 if (cbHint <= 256)
1222 {
1223 if (cbFirst <= 64)
1224 cbBlock = 128;
1225 else
1226 cbBlock = 256;
1227 }
1228 else
1229 cbBlock = 256;
1230 }
1231 else if (cbHint < 2048)
1232 cbBlock = 1024;
1233 else if (cbHint < 3072)
1234 cbBlock = 2048;
1235 else
1236 cbBlock = 4096;
1237
1238 /*
1239 * Allocate and initialize the first block.
1240 */
1241 pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
1242 pNewBlock->cbBlock = cbBlock;
1243 pNewBlock->offNext = sizeof(*pNewBlock) + cbFirst;
1244 pNewBlock->pNext = NULL;
1245 *ppBlockTail = pNewBlock;
1246
1247#ifdef KMK_CC_WITH_STATS
1248 g_cBlockAllocated++;
1249 g_cbAllocated += cbBlock;
1250#endif
1251
1252 return pNewBlock + 1;
1253}
1254
1255
1256/**
1257 * Used for getting the address of the next instruction.
1258 *
1259 * @returns Pointer to the next allocation.
1260 * @param pBlockTail The allocator tail pointer.
1261 */
1262static void *kmk_cc_block_get_next_ptr(PKMKCCBLOCK pBlockTail)
1263{
1264 return (char *)pBlockTail + pBlockTail->offNext;
1265}
1266
1267
1268/**
1269 * Realigns the allocator after doing byte or string allocations.
1270 *
1271 * @param ppBlockTail Pointer to the allocator tail pointer.
1272 */
1273static void kmk_cc_block_realign(PKMKCCBLOCK *ppBlockTail)
1274{
1275 PKMKCCBLOCK pBlockTail = *ppBlockTail;
1276 if (pBlockTail->offNext & (sizeof(void *) - 1))
1277 {
1278 pBlockTail->offNext = (pBlockTail->offNext + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
1279 KMK_CC_ASSERT(pBlockTail->cbBlock - pBlockTail->offNext >= sizeof(KMKCCEXPJUMP));
1280 }
1281}
1282
1283
1284/**
1285 * Grows the allocation with another block, byte allocator case.
1286 *
1287 * @returns Pointer to the byte allocation.
1288 * @param ppBlockTail Pointer to the allocator tail pointer.
1289 * @param cb The number of bytes to allocate.
1290 */
1291static void *kmk_cc_block_byte_alloc_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1292{
1293 PKMKCCBLOCK pOldBlock = *ppBlockTail;
1294 PKMKCCBLOCK pPrevBlock = pOldBlock->pNext;
1295 PKMKCCBLOCK pNewBlock;
1296 uint32_t cbBlock;
1297
1298 /*
1299 * Check if there accidentally is some space left in the previous block first.
1300 */
1301 if ( pPrevBlock
1302 && pPrevBlock->cbBlock - pPrevBlock->offNext >= cb)
1303 {
1304 void *pvRet = (char *)pPrevBlock + pPrevBlock->offNext;
1305 pPrevBlock->offNext += cb;
1306 return pvRet;
1307 }
1308
1309 /*
1310 * Allocate a new block.
1311 */
1312
1313 /* Figure the block size. */
1314 cbBlock = pOldBlock->cbBlock;
1315 while (cbBlock - sizeof(KMKCCEXPJUMP) - sizeof(*pNewBlock) < cb)
1316 cbBlock *= 2;
1317
1318 /* Allocate and initialize the block it with the new instruction already accounted for. */
1319 pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
1320 pNewBlock->cbBlock = cbBlock;
1321 pNewBlock->offNext = sizeof(*pNewBlock) + cb;
1322 pNewBlock->pNext = pOldBlock;
1323 *ppBlockTail = pNewBlock;
1324
1325#ifdef KMK_CC_WITH_STATS
1326 g_cBlockAllocated++;
1327 g_cbAllocated += cbBlock;
1328#endif
1329
1330 return pNewBlock + 1;
1331}
1332
1333
1334/**
1335 * Make a byte allocation.
1336 *
1337 * Must call kmk_cc_block_realign() when done doing byte and string allocations.
1338 *
1339 * @returns Pointer to the byte allocation (byte aligned).
1340 * @param ppBlockTail Pointer to the allocator tail pointer.
1341 * @param cb The number of bytes to allocate.
1342 */
1343static void *kmk_cc_block_byte_alloc(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1344{
1345 PKMKCCBLOCK pBlockTail = *ppBlockTail;
1346 uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;
1347
1348 KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEXPJUMP));
1349 if (cbLeft >= cb + sizeof(KMKCCEXPJUMP))
1350 {
1351 void *pvRet = (char *)pBlockTail + pBlockTail->offNext;
1352 pBlockTail->offNext += cb;
1353 return pvRet;
1354 }
1355 return kmk_cc_block_byte_alloc_grow(ppBlockTail, cb);
1356}
1357
1358
1359/**
1360 * Duplicates the given string in a byte allocation.
1361 *
1362 * Must call kmk_cc_block_realign() when done doing byte and string allocations.
1363 *
1364 * @returns Pointer to the byte allocation (byte aligned).
1365 * @param ppBlockTail Pointer to the allocator tail pointer.
1366 * @param cb The number of bytes to allocate.
1367 */
1368static const char *kmk_cc_block_strdup(PKMKCCBLOCK *ppBlockTail, const char *pachStr, uint32_t cchStr)
1369{
1370 char *pszCopy;
1371 if (cchStr)
1372 {
1373 pszCopy = kmk_cc_block_byte_alloc(ppBlockTail, cchStr + 1);
1374 memcpy(pszCopy, pachStr, cchStr);
1375 pszCopy[cchStr] = '\0';
1376 return pszCopy;
1377 }
1378 return "";
1379}
1380
1381
1382/**
1383 * Grows the allocation with another block, string expansion program case.
1384 *
1385 * @returns Pointer to a string expansion instruction core.
1386 * @param ppBlockTail Pointer to the allocator tail pointer.
1387 * @param cb The number of bytes to allocate.
1388 */
1389static PKMKCCEXPCORE kmk_cc_block_alloc_exp_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1390{
1391 PKMKCCBLOCK pOldBlock = *ppBlockTail;
1392 PKMKCCBLOCK pNewBlock;
1393 PKMKCCEXPCORE pRet;
1394 PKMKCCEXPJUMP pJump;
1395
1396 /* Figure the block size. */
1397 uint32_t cbBlock = !pOldBlock->pNext ? 128 : pOldBlock->cbBlock;
1398 while (cbBlock - sizeof(KMKCCEXPJUMP) - sizeof(*pNewBlock) < cb)
1399 cbBlock *= 2;
1400
1401 /* Allocate and initialize the block it with the new instruction already accounted for. */
1402 pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
1403 pNewBlock->cbBlock = cbBlock;
1404 pNewBlock->offNext = sizeof(*pNewBlock) + cb;
1405 pNewBlock->pNext = pOldBlock;
1406 *ppBlockTail = pNewBlock;
1407
1408#ifdef KMK_CC_WITH_STATS
1409 g_cBlockAllocated++;
1410 g_cbAllocated += cbBlock;
1411#endif
1412
1413 pRet = (PKMKCCEXPCORE)(pNewBlock + 1);
1414
1415 /* Emit jump. */
1416 pJump = (PKMKCCEXPJUMP)((char *)pOldBlock + pOldBlock->offNext);
1417 pJump->Core.enmOpCode = kKmkCcExpInstr_Jump;
1418 pJump->pNext = pRet;
1419 pOldBlock->offNext += sizeof(*pJump);
1420 KMK_CC_ASSERT(pOldBlock->offNext <= pOldBlock->cbBlock);
1421
1422 return pRet;
1423}
1424
1425
1426/**
1427 * Allocates a string expansion instruction of size @a cb.
1428 *
1429 * @returns Pointer to a string expansion instruction core.
1430 * @param ppBlockTail Pointer to the allocator tail pointer.
1431 * @param cb The number of bytes to allocate.
1432 */
1433static PKMKCCEXPCORE kmk_cc_block_alloc_exp(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1434{
1435 PKMKCCBLOCK pBlockTail = *ppBlockTail;
1436 uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;
1437
1438 KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEXPJUMP));
1439 KMK_CC_ASSERT( (cb & (sizeof(void *) - 1)) == 0 || cb == sizeof(KMKCCEXPCORE) /* final */ );
1440
1441 if (cbLeft >= cb + sizeof(KMKCCEXPJUMP))
1442 {
1443 PKMKCCEXPCORE pRet = (PKMKCCEXPCORE)((char *)pBlockTail + pBlockTail->offNext);
1444 pBlockTail->offNext += cb;
1445 return pRet;
1446 }
1447 return kmk_cc_block_alloc_exp_grow(ppBlockTail, cb);
1448}
1449
1450
1451/**
1452 * Grows the allocation with another block, makefile evaluation program case.
1453 *
1454 * @returns Pointer to a makefile evaluation instruction core.
1455 * @param ppBlockTail Pointer to the allocator tail pointer.
1456 * @param cb The number of bytes to allocate.
1457 */
1458static PKMKCCEVALCORE kmk_cc_block_alloc_eval_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1459{
1460 PKMKCCBLOCK pOldBlock = *ppBlockTail;
1461 PKMKCCBLOCK pNewBlock;
1462 PKMKCCEVALCORE pRet;
1463 PKMKCCEVALJUMP pJump;
1464
1465 /* Figure the block size. */
1466 uint32_t cbBlock = !pOldBlock->pNext ? 128 : pOldBlock->cbBlock;
1467 while (cbBlock - sizeof(KMKCCEVALJUMP) - sizeof(*pNewBlock) < cb)
1468 cbBlock *= 2;
1469
1470 /* Allocate and initialize the block it with the new instruction already accounted for. */
1471 pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
1472 pNewBlock->cbBlock = cbBlock;
1473 pNewBlock->offNext = sizeof(*pNewBlock) + cb;
1474 pNewBlock->pNext = pOldBlock;
1475 *ppBlockTail = pNewBlock;
1476
1477#ifdef KMK_CC_WITH_STATS
1478 g_cBlockAllocated++;
1479 g_cbAllocated += cbBlock;
1480#endif
1481
1482 pRet = (PKMKCCEVALCORE)(pNewBlock + 1);
1483
1484 /* Emit jump. */
1485 pJump = (PKMKCCEVALJUMP)((char *)pOldBlock + pOldBlock->offNext);
1486 pJump->Core.enmOpCode = kKmkCcEvalInstr_jump;
1487 pJump->pNext = pRet;
1488 pOldBlock->offNext += sizeof(*pJump);
1489 KMK_CC_ASSERT(pOldBlock->offNext <= pOldBlock->cbBlock);
1490
1491 return pRet;
1492}
1493
1494
1495/**
1496 * Allocates a makefile evaluation instruction of size @a cb.
1497 *
1498 * @returns Pointer to a makefile evaluation instruction core.
1499 * @param ppBlockTail Pointer to the allocator tail pointer.
1500 * @param cb The number of bytes to allocate.
1501 */
1502static PKMKCCEVALCORE kmk_cc_block_alloc_eval(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1503{
1504 PKMKCCBLOCK pBlockTail = *ppBlockTail;
1505 uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;
1506
1507 KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEVALJUMP));
1508 KMK_CC_ASSERT( (cb & (sizeof(void *) - 1)) == 0 );
1509
1510 if (cbLeft >= cb + sizeof(KMKCCEVALJUMP))
1511 {
1512 PKMKCCEVALCORE pRet = (PKMKCCEVALCORE)((char *)pBlockTail + pBlockTail->offNext);
1513 pBlockTail->offNext += cb;
1514 return pRet;
1515 }
1516 return kmk_cc_block_alloc_eval_grow(ppBlockTail, cb);
1517}
1518
1519
1520/**
1521 * Allocate a string buffer for a makefile evaluation program.
1522 *
1523 * @returns Pointer to a makefile evaluation instruction core.
1524 * @param ppBlockTail Pointer to the allocator tail pointer.
1525 * @param cb The number of bytes to allocate.
1526 */
1527static char *kmk_cc_block_alloc_eval_string(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1528{
1529 PKMKCCBLOCK pBlockTail = *ppBlockTail;
1530 uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;
1531
1532 KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEVALJUMP));
1533
1534 cb = (cb + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
1535 if (cbLeft >= cb + sizeof(KMKCCEVALJUMP))
1536 {
1537 char *pszRet = (char *)pBlockTail + pBlockTail->offNext;
1538 pBlockTail->offNext += cb;
1539 return pszRet;
1540 }
1541 return (char *)kmk_cc_block_alloc_eval_grow(ppBlockTail, cb);
1542}
1543
1544
1545/**
1546 * Frees all memory used by an allocator.
1547 *
1548 * @param ppBlockTail The allocator tail pointer.
1549 */
1550static void kmk_cc_block_free_list(PKMKCCBLOCK pBlockTail)
1551{
1552 while (pBlockTail)
1553 {
1554 PKMKCCBLOCK pThis = pBlockTail;
1555 pBlockTail = pBlockTail->pNext;
1556 free(pThis);
1557 }
1558}
1559
1560
1561/*
1562 *
1563 * The string expansion compiler.
1564 * The string expansion compiler.
1565 * The string expansion compiler.
1566 *
1567 */
1568
1569
1570/**
1571 * Emits a kKmkCcExpInstr_Return.
1572 *
1573 * @param ppBlockTail Pointer to the allocator tail pointer.
1574 */
1575static void kmk_cc_exp_emit_return(PKMKCCBLOCK *ppBlockTail)
1576{
1577 PKMKCCEXPCORE pCore = kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pCore));
1578 pCore->enmOpCode = kKmkCcExpInstr_Return;
1579}
1580
1581
1582/**
1583 * Checks if a function is known to mess up the arguments its given.
1584 *
1585 * When executing calls to "dirty" functions, all arguments must be duplicated
1586 * on the heap.
1587 *
1588 * @returns 1 if dirty, 0 if clean.
1589 * @param pszFunction The function name.
1590 */
1591static uint8_t kmk_cc_is_dirty_function(const char *pszFunction)
1592{
1593 switch (pszFunction[0])
1594 {
1595 default:
1596 return 0;
1597
1598 case 'e':
1599 if (!strcmp(pszFunction, "eval"))
1600 return 1;
1601 if (!strcmp(pszFunction, "evalctx"))
1602 return 1;
1603 return 0;
1604
1605 case 'f':
1606 if (!strcmp(pszFunction, "filter"))
1607 return 1;
1608 if (!strcmp(pszFunction, "filter-out"))
1609 return 1;
1610 if (!strcmp(pszFunction, "for"))
1611 return 1;
1612 return 0;
1613
1614 case 's':
1615 if (!strcmp(pszFunction, "sort"))
1616 return 1;
1617 return 0;
1618 }
1619}
1620
1621
1622/**
1623 * Emits a function call instruction taking arguments that needs expanding.
1624 *
1625 * @returns 0 on success, non-zero on failure.
1626 * @param ppBlockTail Pointer to the allocator tail pointer.
1627 * @param pszFunction The function name (const string from function.c).
1628 * @param pchArgs Pointer to the arguments expression string, leading
1629 * any blanks has been stripped.
1630 * @param cchArgs The length of the arguments expression string.
1631 * @param cArgs Number of arguments found.
1632 * @param chOpen The char used to open the function call.
1633 * @param chClose The char used to close the function call.
1634 * @param pfnFunction The function implementation.
1635 * @param cMaxArgs Maximum number of arguments the function takes.
1636 */
1637static int kmk_cc_exp_emit_dyn_function(PKMKCCBLOCK *ppBlockTail, const char *pszFunction,
1638 const char *pchArgs, uint32_t cchArgs, uint32_t cArgs, char chOpen, char chClose,
1639 make_function_ptr_t pfnFunction, unsigned char cMaxArgs)
1640{
1641 uint32_t iArg;
1642
1643 /*
1644 * The function instruction has variable size. The maximum argument count
1645 * isn't quite like the minium one. Zero means no limit. While a non-zero
1646 * value means that any commas beyond the max will be taken to be part of
1647 * the final argument.
1648 */
1649 uint32_t cActualArgs = cArgs <= cMaxArgs || !cMaxArgs ? cArgs : cMaxArgs;
1650 PKMKCCEXPDYNFUNC pInstr = (PKMKCCEXPDYNFUNC)kmk_cc_block_alloc_exp(ppBlockTail, KMKCCEXPDYNFUNC_SIZE(cActualArgs));
1651 pInstr->FnCore.Core.enmOpCode = kKmkCcExpInstr_DynamicFunction;
1652 pInstr->FnCore.cArgs = cActualArgs;
1653 pInstr->FnCore.pfnFunction = pfnFunction;
1654 pInstr->FnCore.pszFuncName = pszFunction;
1655 pInstr->FnCore.fDirty = kmk_cc_is_dirty_function(pszFunction);
1656
1657 /*
1658 * Parse the arguments. Plain arguments gets duplicated in the program
1659 * memory so that they are terminated and no extra processing is necessary
1660 * later on. ASSUMES that the function implementations do NOT change
1661 * argument memory. Other arguments the compiled into their own expansion
1662 * sub programs.
1663 */
1664 iArg = 0;
1665 for (;;)
1666 {
1667 /* Find the end of the argument. Check for $. */
1668 char ch = '\0';
1669 uint8_t fDollar = 0;
1670 int32_t cDepth = 0;
1671 uint32_t cchThisArg = 0;
1672 while (cchThisArg < cchArgs)
1673 {
1674 ch = pchArgs[cchThisArg];
1675 if (ch == chClose)
1676 {
1677 KMK_CC_ASSERT(cDepth > 0);
1678 if (cDepth > 0)
1679 cDepth--;
1680 }
1681 else if (ch == chOpen)
1682 cDepth++;
1683 else if (ch == ',' && cDepth == 0 && iArg + 1 < cActualArgs)
1684 break;
1685 else if (ch == '$')
1686 fDollar = 1;
1687 cchThisArg++;
1688 }
1689
1690 pInstr->aArgs[iArg].fSubprog = fDollar;
1691 if (fDollar)
1692 {
1693 /* Compile it. */
1694 int rc;
1695 kmk_cc_block_realign(ppBlockTail);
1696 rc = kmk_cc_exp_compile_subprog(ppBlockTail, pchArgs, cchThisArg, &pInstr->aArgs[iArg].u.Subprog);
1697 if (rc != 0)
1698 return rc;
1699 }
1700 else
1701 {
1702 /* Duplicate it. */
1703 pInstr->aArgs[iArg].u.Plain.psz = kmk_cc_block_strdup(ppBlockTail, pchArgs, cchThisArg);
1704 pInstr->aArgs[iArg].u.Plain.cch = cchThisArg;
1705 }
1706 iArg++;
1707 if (ch != ',')
1708 break;
1709 pchArgs += cchThisArg + 1;
1710 cchArgs -= cchThisArg + 1;
1711 }
1712 KMK_CC_ASSERT(iArg == cActualArgs);
1713
1714 /*
1715 * Realign the allocator and take down the address of the next instruction.
1716 */
1717 kmk_cc_block_realign(ppBlockTail);
1718 pInstr->FnCore.pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1719 return 0;
1720}
1721
1722
1723/**
1724 * Emits a function call instruction taking plain arguments.
1725 *
1726 * @returns 0 on success, non-zero on failure.
1727 * @param ppBlockTail Pointer to the allocator tail pointer.
1728 * @param pszFunction The function name (const string from function.c).
1729 * @param pchArgs Pointer to the arguments string, leading any blanks
1730 * has been stripped.
1731 * @param cchArgs The length of the arguments string.
1732 * @param cArgs Number of arguments found.
1733 * @param chOpen The char used to open the function call.
1734 * @param chClose The char used to close the function call.
1735 * @param pfnFunction The function implementation.
1736 * @param cMaxArgs Maximum number of arguments the function takes.
1737 */
1738static void kmk_cc_exp_emit_plain_function(PKMKCCBLOCK *ppBlockTail, const char *pszFunction,
1739 const char *pchArgs, uint32_t cchArgs, uint32_t cArgs, char chOpen, char chClose,
1740 make_function_ptr_t pfnFunction, unsigned char cMaxArgs)
1741{
1742 uint32_t iArg;
1743
1744 /*
1745 * The function instruction has variable size. The maximum argument count
1746 * isn't quite like the minium one. Zero means no limit. While a non-zero
1747 * value means that any commas beyond the max will be taken to be part of
1748 * the final argument.
1749 */
1750 uint32_t cActualArgs = cArgs <= cMaxArgs || !cMaxArgs ? cArgs : cMaxArgs;
1751 PKMKCCEXPPLAINFUNC pInstr = (PKMKCCEXPPLAINFUNC)kmk_cc_block_alloc_exp(ppBlockTail, KMKCCEXPPLAINFUNC_SIZE(cActualArgs));
1752 pInstr->FnCore.Core.enmOpCode = kKmkCcExpInstr_PlainFunction;
1753 pInstr->FnCore.cArgs = cActualArgs;
1754 pInstr->FnCore.pfnFunction = pfnFunction;
1755 pInstr->FnCore.pszFuncName = pszFunction;
1756 pInstr->FnCore.fDirty = kmk_cc_is_dirty_function(pszFunction);
1757
1758 /*
1759 * Parse the arguments. Plain arguments gets duplicated in the program
1760 * memory so that they are terminated and no extra processing is necessary
1761 * later on. ASSUMES that the function implementations do NOT change
1762 * argument memory.
1763 */
1764 iArg = 0;
1765 for (;;)
1766 {
1767 /* Find the end of the argument. */
1768 char ch = '\0';
1769 int32_t cDepth = 0;
1770 uint32_t cchThisArg = 0;
1771 while (cchThisArg < cchArgs)
1772 {
1773 ch = pchArgs[cchThisArg];
1774 if (ch == chClose)
1775 {
1776 KMK_CC_ASSERT(cDepth > 0);
1777 if (cDepth > 0)
1778 cDepth--;
1779 }
1780 else if (ch == chOpen)
1781 cDepth++;
1782 else if (ch == ',' && cDepth == 0 && iArg + 1 < cActualArgs)
1783 break;
1784 cchThisArg++;
1785 }
1786
1787 /* Duplicate it. */
1788 pInstr->apszArgs[iArg++] = kmk_cc_block_strdup(ppBlockTail, pchArgs, cchThisArg);
1789 if (ch != ',')
1790 break;
1791 pchArgs += cchThisArg + 1;
1792 cchArgs -= cchThisArg + 1;
1793 }
1794
1795 KMK_CC_ASSERT(iArg == cActualArgs);
1796 pInstr->apszArgs[iArg] = NULL;
1797
1798 /*
1799 * Realign the allocator and take down the address of the next instruction.
1800 */
1801 kmk_cc_block_realign(ppBlockTail);
1802 pInstr->FnCore.pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1803}
1804
1805
1806/**
1807 * Emits a kKmkCcExpInstr_DynamicVariable.
1808 *
1809 * @returns 0 on success, non-zero on failure.
1810 * @param ppBlockTail Pointer to the allocator tail pointer.
1811 * @param pchNameExpr The name of the variable (ASSUMED presistent
1812 * thru-out the program life time).
1813 * @param cchNameExpr The length of the variable name. If zero,
1814 * nothing will be emitted.
1815 */
1816static int kmk_cc_exp_emit_dyn_variable(PKMKCCBLOCK *ppBlockTail, const char *pchNameExpr, uint32_t cchNameExpr)
1817{
1818 PKMKCCEXPDYNVAR pInstr;
1819 int rc;
1820 KMK_CC_ASSERT(cchNameExpr > 0);
1821
1822 pInstr = (PKMKCCEXPDYNVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1823 pInstr->Core.enmOpCode = kKmkCcExpInstr_DynamicVariable;
1824
1825 rc = kmk_cc_exp_compile_subprog(ppBlockTail, pchNameExpr, cchNameExpr, &pInstr->Subprog);
1826
1827 pInstr->pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1828 return rc;
1829}
1830
1831
1832/**
1833 * Emits either a kKmkCcExpInstr_PlainVariable or
1834 * kKmkCcExpInstr_SearchAndReplacePlainVariable instruction.
1835 *
1836 * @param ppBlockTail Pointer to the allocator tail pointer.
1837 * @param pchName The name of the variable. (Does not need to be
1838 * valid beyond the call.)
1839 * @param cchName The length of the variable name. If zero,
1840 * nothing will be emitted.
1841 */
1842static void kmk_cc_exp_emit_plain_variable_maybe_sr(PKMKCCBLOCK *ppBlockTail, const char *pchName, uint32_t cchName)
1843{
1844 if (cchName > 0)
1845 {
1846 /*
1847 * Hopefully, we're not expected to do any search and replace on the
1848 * expanded variable string later... Requires both ':' and '='.
1849 */
1850 const char *pchEqual;
1851 const char *pchColon = (const char *)memchr(pchName, ':', cchName);
1852 if ( pchColon == NULL
1853 || (pchEqual = (const char *)memchr(pchColon + 1, ':', cchName - (pchColon - pchName - 1))) == NULL
1854 || pchEqual == pchEqual + 1)
1855 {
1856 PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1857 pInstr->Core.enmOpCode = kKmkCcExpInstr_PlainVariable;
1858 pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName);
1859 }
1860 else if (pchColon != pchName)
1861 {
1862 /*
1863 * Okay, we need to do search and replace the variable value.
1864 * This is performed by patsubst_expand_pat using '%' patterns.
1865 */
1866 uint32_t cchName2 = (uint32_t)(pchColon - pchName);
1867 uint32_t cchSearch = (uint32_t)(pchEqual - pchColon - 1);
1868 uint32_t cchReplace = cchName - cchName2 - cchSearch - 2;
1869 const char *pchPct;
1870 char *psz;
1871 PKMKCCEXPSRPLAINVAR pInstr;
1872
1873 pInstr = (PKMKCCEXPSRPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1874 pInstr->Core.enmOpCode = kKmkCcExpInstr_SearchAndReplacePlainVariable;
1875 pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName2);
1876
1877 /* Figure out the search pattern, unquoting percent chars.. */
1878 psz = (char *)kmk_cc_block_byte_alloc(ppBlockTail, cchSearch + 2);
1879 psz[0] = '%';
1880 memcpy(psz + 1, pchColon + 1, cchSearch);
1881 psz[1 + cchSearch] = '\0';
1882 pchPct = find_percent(psz + 1); /* also performs unquoting */
1883 if (pchPct)
1884 {
1885 pInstr->pszSearchPattern = psz + 1;
1886 pInstr->offPctSearchPattern = (uint32_t)(pchPct - psz - 1);
1887 }
1888 else
1889 {
1890 pInstr->pszSearchPattern = psz;
1891 pInstr->offPctSearchPattern = 0;
1892 }
1893
1894 /* Figure out the replacement pattern, unquoting percent chars.. */
1895 if (cchReplace == 0)
1896 {
1897 pInstr->pszReplacePattern = "%";
1898 pInstr->offPctReplacePattern = 0;
1899 }
1900 else
1901 {
1902 psz = (char *)kmk_cc_block_byte_alloc(ppBlockTail, cchReplace + 2);
1903 psz[0] = '%';
1904 memcpy(psz + 1, pchEqual + 1, cchReplace);
1905 psz[1 + cchReplace] = '\0';
1906 pchPct = find_percent(psz + 1); /* also performs unquoting */
1907 if (pchPct)
1908 {
1909 pInstr->pszReplacePattern = psz + 1;
1910 pInstr->offPctReplacePattern = (uint32_t)(pchPct - psz - 1);
1911 }
1912 else
1913 {
1914 pInstr->pszReplacePattern = psz;
1915 pInstr->offPctReplacePattern = 0;
1916 }
1917 }
1918
1919 /* Note down where the next instruction is after realigning the allocator. */
1920 kmk_cc_block_realign(ppBlockTail);
1921 pInstr->pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1922 }
1923 }
1924}
1925
1926
1927/**
1928 * Emits a kKmkCcExpInstr_CopyString.
1929 *
1930 * @param ppBlockTail Pointer to the allocator tail pointer.
1931 * @param pchStr The string to emit (ASSUMED presistent thru-out
1932 * the program life time).
1933 * @param cchStr The number of chars to copy. If zero, nothing
1934 * will be emitted.
1935 */
1936static void kmk_cc_exp_emit_copy_string(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr)
1937{
1938 if (cchStr > 0)
1939 {
1940 PKMKCCEXPCOPYSTRING pInstr = (PKMKCCEXPCOPYSTRING)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1941 pInstr->Core.enmOpCode = kKmkCcExpInstr_CopyString;
1942 pInstr->cchCopy = cchStr;
1943 pInstr->pachSrc = pchStr;
1944 }
1945}
1946
1947
1948/**
1949 * String expansion compilation function common to both normal and sub programs.
1950 *
1951 * @returns 0 on success, non-zero on failure.
1952 * @param ppBlockTail Pointer to the allocator tail pointer.
1953 * @param pchStr The expression to compile.
1954 * @param cchStr The length of the expression to compile.
1955 */
1956static int kmk_cc_exp_compile_common(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr)
1957{
1958 /*
1959 * Process the string.
1960 */
1961 while (cchStr > 0)
1962 {
1963 /* Look for dollar sign, marks variable expansion or dollar-escape. */
1964 int rc;
1965 const char *pchDollar = memchr(pchStr, '$', cchStr);
1966 if (pchDollar)
1967 {
1968 /*
1969 * Check for multiple dollar chars.
1970 */
1971 uint32_t offDollar = (uint32_t)(pchDollar - pchStr);
1972 uint32_t cDollars = 1;
1973 while ( offDollar + cDollars < cchStr
1974 && pchStr[offDollar + cDollars] == '$')
1975 cDollars++;
1976
1977 /*
1978 * Emit a string copy for any preceeding stuff, including half of
1979 * the dollars we found (dollar escape: $$ -> $).
1980 * (kmk_cc_exp_emit_copy_string ignore zero length strings).
1981 */
1982 kmk_cc_exp_emit_copy_string(ppBlockTail, pchStr, offDollar + cDollars / 2);
1983 pchStr += offDollar + cDollars;
1984 cchStr -= offDollar + cDollars;
1985
1986 /*
1987 * Odd number of dollar chars means there is a variable to expand
1988 * or function to call.
1989 */
1990 if (cDollars & 1)
1991 {
1992 if (cchStr > 0)
1993 {
1994 char const chOpen = *pchStr;
1995 if (chOpen == '(' || chOpen == '{')
1996 {
1997 /* There are several alternative ways of finding the ending
1998 parenthesis / braces.
1999
2000 GNU make does one thing for functions and variable containing
2001 any '$' chars before the first closing char. While for
2002 variables where a closing char comes before any '$' char, a
2003 simplified approach is taken. This means that for example:
2004
2005 Given VAR=var, the expressions "$(var())" and
2006 "$($(VAR)())" would be expanded differently.
2007 In the first case the variable "var(" would be
2008 used and in the second "var()".
2009
2010 This code will not duplicate this weird behavior, but work
2011 the same regardless of whether there is a '$' char before
2012 the first closing char. */
2013 make_function_ptr_t pfnFunction;
2014 const char *pszFunction;
2015 unsigned char cMaxArgs;
2016 unsigned char cMinArgs;
2017 char fExpandArgs;
2018 char const chClose = chOpen == '(' ? ')' : '}';
2019 char ch = 0;
2020 uint32_t cchName = 0;
2021 uint32_t cDepth = 1;
2022 uint32_t cMaxDepth = 1;
2023 cDollars = 0;
2024
2025 pchStr++;
2026 cchStr--;
2027
2028 /* First loop: Identify potential function calls and dynamic expansion. */
2029 KMK_CC_ASSERT(!func_char_map[(unsigned char)chOpen]);
2030 KMK_CC_ASSERT(!func_char_map[(unsigned char)chClose]);
2031 KMK_CC_ASSERT(!func_char_map[(unsigned char)'$']);
2032 while (cchName < cchStr)
2033 {
2034 ch = pchStr[cchName];
2035 if (!func_char_map[(unsigned char)ch])
2036 break;
2037 cchName++;
2038 }
2039
2040 if ( cchName >= MIN_FUNCTION_LENGTH
2041 && cchName <= MAX_FUNCTION_LENGTH
2042 && (isblank(ch) || ch == chClose || cchName == cchStr)
2043 && (pfnFunction = lookup_function_for_compiler(pchStr, cchName, &cMinArgs, &cMaxArgs,
2044 &fExpandArgs, &pszFunction)) != NULL)
2045 {
2046 /*
2047 * It's a function invocation, we should count parameters while
2048 * looking for the end.
2049 * Note! We use cchName for the length of the argument list.
2050 */
2051 uint32_t cArgs = 1;
2052 if (ch != chClose)
2053 {
2054 /* Skip leading spaces before the first arg. */
2055 cchName++;
2056 while (cchName < cchStr && isblank((unsigned char)pchStr[cchName]))
2057 cchName++;
2058
2059 pchStr += cchName;
2060 cchStr -= cchName;
2061 cchName = 0;
2062
2063 while (cchName < cchStr)
2064 {
2065 ch = pchStr[cchName];
2066 if (ch == ',')
2067 {
2068 if (cDepth == 1)
2069 cArgs++;
2070 }
2071 else if (ch == chClose)
2072 {
2073 if (!--cDepth)
2074 break;
2075 }
2076 else if (ch == chOpen)
2077 {
2078 if (++cDepth > cMaxDepth)
2079 cMaxDepth = cDepth;
2080 }
2081 else if (ch == '$')
2082 cDollars++;
2083 cchName++;
2084 }
2085 }
2086 else
2087 {
2088 pchStr += cchName;
2089 cchStr -= cchName;
2090 cchName = 0;
2091 }
2092 if (cArgs < cMinArgs)
2093 {
2094 fatal(NULL, _("Function '%s' takes a minimum of %d arguments: %d given"),
2095 pszFunction, (int)cMinArgs, (int)cArgs);
2096 return -1; /* not reached */
2097 }
2098 if (cDepth != 0)
2099 {
2100 fatal(NULL, chOpen == '('
2101 ? _("Missing closing parenthesis calling '%s'") : _("Missing closing braces calling '%s'"),
2102 pszFunction);
2103 return -1; /* not reached */
2104 }
2105 if (cMaxDepth > 16 && fExpandArgs)
2106 {
2107 fatal(NULL, _("Too many levels of nested function arguments expansions: %s"), pszFunction);
2108 return -1; /* not reached */
2109 }
2110 if (!fExpandArgs || cDollars == 0)
2111 kmk_cc_exp_emit_plain_function(ppBlockTail, pszFunction, pchStr, cchName,
2112 cArgs, chOpen, chClose, pfnFunction, cMaxArgs);
2113 else
2114 {
2115 rc = kmk_cc_exp_emit_dyn_function(ppBlockTail, pszFunction, pchStr, cchName,
2116 cArgs, chOpen, chClose, pfnFunction, cMaxArgs);
2117 if (rc != 0)
2118 return rc;
2119 }
2120 }
2121 else
2122 {
2123 /*
2124 * Variable, find the end while checking whether anything needs expanding.
2125 */
2126 if (ch == chClose)
2127 cDepth = 0;
2128 else if (cchName < cchStr)
2129 {
2130 if (ch != '$')
2131 {
2132 /* Second loop: Look for things that needs expanding. */
2133 while (cchName < cchStr)
2134 {
2135 ch = pchStr[cchName];
2136 if (ch == chClose)
2137 {
2138 if (!--cDepth)
2139 break;
2140 }
2141 else if (ch == chOpen)
2142 {
2143 if (++cDepth > cMaxDepth)
2144 cMaxDepth = cDepth;
2145 }
2146 else if (ch == '$')
2147 break;
2148 cchName++;
2149 }
2150 }
2151 if (ch == '$')
2152 {
2153 /* Third loop: Something needs expanding, just find the end. */
2154 cDollars = 1;
2155 cchName++;
2156 while (cchName < cchStr)
2157 {
2158 ch = pchStr[cchName];
2159 if (ch == chClose)
2160 {
2161 if (!--cDepth)
2162 break;
2163 }
2164 else if (ch == chOpen)
2165 {
2166 if (++cDepth > cMaxDepth)
2167 cMaxDepth = cDepth;
2168 }
2169 cchName++;
2170 }
2171 }
2172 }
2173 if (cDepth > 0) /* After warning, we just assume they're all there. */
2174 error(NULL, chOpen == '(' ? _("Missing closing parenthesis ") : _("Missing closing braces"));
2175 if (cMaxDepth >= 16)
2176 {
2177 fatal(NULL, _("Too many levels of nested variable expansions: '%.*s'"), (int)cchName + 2, pchStr - 1);
2178 return -1; /* not reached */
2179 }
2180 if (cDollars == 0)
2181 kmk_cc_exp_emit_plain_variable_maybe_sr(ppBlockTail, pchStr, cchName);
2182 else
2183 {
2184 rc = kmk_cc_exp_emit_dyn_variable(ppBlockTail, pchStr, cchName);
2185 if (rc != 0)
2186 return rc;
2187 }
2188 }
2189 pchStr += cchName + 1;
2190 cchStr -= cchName + (cDepth == 0);
2191 }
2192 else
2193 {
2194 /* Single character variable name. */
2195 kmk_cc_exp_emit_plain_variable_maybe_sr(ppBlockTail, pchStr, 1);
2196 pchStr++;
2197 cchStr--;
2198 }
2199 }
2200 else
2201 {
2202 error(NULL, _("Unexpected end of string after $"));
2203 break;
2204 }
2205 }
2206 }
2207 else
2208 {
2209 /*
2210 * Nothing more to expand, the remainder is a simple string copy.
2211 */
2212 kmk_cc_exp_emit_copy_string(ppBlockTail, pchStr, cchStr);
2213 break;
2214 }
2215 }
2216
2217 /*
2218 * Emit final instruction.
2219 */
2220 kmk_cc_exp_emit_return(ppBlockTail);
2221 return 0;
2222}
2223
2224
2225/**
2226 * Initializes string expansion program statistics.
2227 * @param pStats Pointer to the statistics structure to init.
2228 */
2229static void kmk_cc_exp_stats_init(PKMKCCEXPSTATS pStats)
2230{
2231 pStats->cchAvg = 0;
2232}
2233
2234
2235/**
2236 * Compiles a string expansion subprogram.
2237 *
2238 * The caller typically make a call to kmk_cc_block_get_next_ptr after this
2239 * function returns to figure out where to continue executing.
2240 *
2241 * @returns 0 on success, non-zero on failure.
2242 * @param ppBlockTail Pointer to the allocator tail pointer.
2243 * @param pchStr Pointer to the string to compile an expansion
2244 * program for (ASSUMED to be valid for the
2245 * lifetime of the program).
2246 * @param cchStr The length of the string to compile. Expected to
2247 * be at least on char long.
2248 * @param pSubprog The subprogram structure to initialize.
2249 */
2250static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubprog)
2251{
2252 KMK_CC_ASSERT(cchStr > 0);
2253 pSubprog->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
2254 kmk_cc_exp_stats_init(&pSubprog->Stats);
2255 return kmk_cc_exp_compile_common(ppBlockTail, pchStr, cchStr);
2256}
2257
2258
2259/**
2260 * Compiles a string expansion program.
2261 *
2262 * @returns Pointer to the program on success, NULL on failure.
2263 * @param pchStr Pointer to the string to compile an expansion
2264 * program for (ASSUMED to be valid for the
2265 * lifetime of the program).
2266 * @param cchStr The length of the string to compile. Expected to
2267 * be at least on char long.
2268 */
2269static PKMKCCEXPPROG kmk_cc_exp_compile(const char *pchStr, uint32_t cchStr)
2270{
2271 /*
2272 * Estimate block size, allocate one and initialize it.
2273 */
2274 PKMKCCEXPPROG pProg;
2275 PKMKCCBLOCK pBlock;
2276 pProg = kmk_cc_block_alloc_first(&pBlock, sizeof(*pProg),
2277 (kmk_cc_count_dollars(pchStr, cchStr) + 4) * 8);
2278 if (pProg)
2279 {
2280 pProg->pBlockTail = pBlock;
2281 pProg->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(pBlock);
2282 kmk_cc_exp_stats_init(&pProg->Stats);
2283 pProg->cRefs = 1;
2284#ifdef KMK_CC_STRICT
2285 pProg->uInputHash = kmk_cc_debug_string_hash_n(0, pchStr, cchStr);
2286#endif
2287
2288 /*
2289 * Join forces with the subprogram compilation code.
2290 */
2291 if (kmk_cc_exp_compile_common(&pProg->pBlockTail, pchStr, cchStr) == 0)
2292 {
2293#ifdef KMK_CC_WITH_STATS
2294 pBlock = pProg->pBlockTail;
2295 if (!pBlock->pNext)
2296 g_cSingleBlockExpProgs++;
2297 else if (!pBlock->pNext->pNext)
2298 g_cTwoBlockExpProgs++;
2299 else
2300 g_cMultiBlockExpProgs++;
2301 for (; pBlock; pBlock = pBlock->pNext)
2302 {
2303 g_cBlocksAllocatedExpProgs++;
2304 g_cbAllocatedExpProgs += pBlock->cbBlock;
2305 g_cbUnusedMemExpProgs += pBlock->cbBlock - pBlock->offNext;
2306 }
2307#endif
2308 return pProg;
2309 }
2310 kmk_cc_block_free_list(pProg->pBlockTail);
2311 }
2312 return NULL;
2313}
2314
2315
2316/**
2317 * Updates the recursive_without_dollar member of a variable structure.
2318 *
2319 * This avoid compiling string expansion programs without only a CopyString
2320 * instruction. By setting recursive_without_dollar to 1, code calling
2321 * kmk_cc_compile_variable_for_expand and kmk_exec_expand_to_var_buf will
2322 * instead treat start treating it as a simple variable, which is faster.
2323 *
2324 * @returns The updated recursive_without_dollar value.
2325 * @param pVar Pointer to the variable.
2326 */
2327static int kmk_cc_update_variable_recursive_without_dollar(struct variable *pVar)
2328{
2329 int fValue;
2330 KMK_CC_ASSERT(pVar->recursive_without_dollar == 0);
2331
2332 if (memchr(pVar->value, '$', pVar->value_length))
2333 fValue = -1;
2334 else
2335 fValue = 1;
2336 pVar->recursive_without_dollar = fValue;
2337
2338 return fValue;
2339}
2340
2341
2342/**
2343 * Compiles a variable for string expansion.
2344 *
2345 * @returns Pointer to the string expansion program on success, NULL if no
2346 * program was created.
2347 * @param pVar Pointer to the variable.
2348 */
2349struct kmk_cc_expandprog *kmk_cc_compile_variable_for_expand(struct variable *pVar)
2350{
2351 KMK_CC_ASSERT(strlen(pVar->value) == pVar->value_length);
2352 KMK_CC_ASSERT(!pVar->expandprog);
2353 KMK_CC_ASSERT(pVar->recursive_without_dollar <= 0);
2354
2355 if ( !pVar->expandprog
2356 && pVar->recursive)
2357 {
2358 if ( pVar->recursive_without_dollar < 0
2359 || ( pVar->recursive_without_dollar == 0
2360 && kmk_cc_update_variable_recursive_without_dollar(pVar) < 0) )
2361 {
2362 pVar->expandprog = kmk_cc_exp_compile(pVar->value, pVar->value_length);
2363 g_cVarForExpandCompilations++;
2364 }
2365 }
2366 return pVar->expandprog;
2367}
2368
2369
2370/**
2371 * String expansion execution worker for outputting a variable.
2372 *
2373 * @returns The new variable buffer position.
2374 * @param pVar The variable to reference.
2375 * @param pchDst The current variable buffer position.
2376 */
2377static char *kmk_exec_expand_worker_reference_variable(struct variable *pVar, char *pchDst)
2378{
2379 if (pVar->value_length > 0)
2380 {
2381 if (!pVar->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar))
2382 pchDst = variable_buffer_output(pchDst, pVar->value, pVar->value_length);
2383 else
2384 pchDst = reference_recursive_variable(pchDst, pVar);
2385 }
2386 else if (pVar->append)
2387 pchDst = reference_recursive_variable(pchDst, pVar);
2388 return pchDst;
2389}
2390
2391
2392/**
2393 * Executes a stream string expansion instructions, outputting to the current
2394 * varaible buffer.
2395 *
2396 * @returns The new variable buffer position.
2397 * @param pInstrCore The instruction to start executing at.
2398 * @param pchDst The current variable buffer position.
2399 */
2400static char *kmk_exec_expand_instruction_stream_to_var_buf(PKMKCCEXPCORE pInstrCore, char *pchDst)
2401{
2402 for (;;)
2403 {
2404 switch (pInstrCore->enmOpCode)
2405 {
2406 case kKmkCcExpInstr_CopyString:
2407 {
2408 PKMKCCEXPCOPYSTRING pInstr = (PKMKCCEXPCOPYSTRING)pInstrCore;
2409 pchDst = variable_buffer_output(pchDst, pInstr->pachSrc, pInstr->cchCopy);
2410
2411 pInstrCore = &(pInstr + 1)->Core;
2412 break;
2413 }
2414
2415 case kKmkCcExpInstr_PlainVariable:
2416 {
2417 PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)pInstrCore;
2418 struct variable *pVar = lookup_variable_strcached(pInstr->pszName);
2419 if (pVar)
2420 pchDst = kmk_exec_expand_worker_reference_variable(pVar, pchDst);
2421 else
2422 warn_undefined(pInstr->pszName, strcache2_get_len(&variable_strcache, pInstr->pszName));
2423
2424 pInstrCore = &(pInstr + 1)->Core;
2425 break;
2426 }
2427
2428 case kKmkCcExpInstr_DynamicVariable:
2429 {
2430 PKMKCCEXPDYNVAR pInstr = (PKMKCCEXPDYNVAR)pInstrCore;
2431 struct variable *pVar;
2432 uint32_t cchName;
2433 char *pszName = kmk_exec_expand_subprog_to_tmp(&pInstr->Subprog, &cchName);
2434 char *pszColon = (char *)memchr(pszName, ':', cchName);
2435 char *pszEqual;
2436 if ( pszColon == NULL
2437 || (pszEqual = (char *)memchr(pszColon + 1, '=', &pszName[cchName] - pszColon - 1)) == NULL
2438 || pszEqual == pszColon + 1)
2439 {
2440 pVar = lookup_variable(pszName, cchName);
2441 if (pVar)
2442 pchDst = kmk_exec_expand_worker_reference_variable(pVar, pchDst);
2443 else
2444 warn_undefined(pszName, cchName);
2445 }
2446 else if (pszColon != pszName)
2447 {
2448 /*
2449 * Oh, we have to do search and replace. How tedious.
2450 * Since the variable name is a temporary buffer, we can transform
2451 * the strings into proper search and replacement patterns directly.
2452 */
2453 pVar = lookup_variable(pszName, pszColon - pszName);
2454 if (pVar)
2455 {
2456 char const *pszExpandedVarValue = pVar->recursive ? recursively_expand(pVar) : pVar->value;
2457 char *pszSearchPat = pszColon + 1;
2458 char *pszReplacePat = pszEqual + 1;
2459 const char *pchPctSearchPat;
2460 const char *pchPctReplacePat;
2461
2462 *pszEqual = '\0';
2463 pchPctSearchPat = find_percent(pszSearchPat);
2464 pchPctReplacePat = find_percent(pszReplacePat);
2465
2466 if (!pchPctReplacePat)
2467 {
2468 if (pszReplacePat[-2] != '\0') /* On the offchance that a pct was unquoted by find_percent. */
2469 {
2470 memmove(pszName + 1, pszSearchPat, pszReplacePat - pszSearchPat);
2471 if (pchPctSearchPat)
2472 pchPctSearchPat -= pszSearchPat - &pszName[1];
2473 pszSearchPat = &pszName[1];
2474 }
2475 pchPctReplacePat = --pszReplacePat;
2476 *pszReplacePat = '%';
2477 }
2478
2479 if (!pchPctSearchPat)
2480 {
2481 pchPctSearchPat = --pszSearchPat;
2482 *pszSearchPat = '%';
2483 }
2484
2485 pchDst = patsubst_expand_pat(pchDst, pszExpandedVarValue,
2486 pszSearchPat, pszReplacePat,
2487 pchPctSearchPat, pchPctReplacePat);
2488
2489 if (pVar->recursive)
2490 free((void *)pszExpandedVarValue);
2491 }
2492 else
2493 warn_undefined(pszName, pszColon - pszName);
2494 }
2495 free(pszName);
2496
2497 pInstrCore = pInstr->pNext;
2498 break;
2499 }
2500
2501
2502 case kKmkCcExpInstr_SearchAndReplacePlainVariable:
2503 {
2504 PKMKCCEXPSRPLAINVAR pInstr = (PKMKCCEXPSRPLAINVAR)pInstrCore;
2505 struct variable *pVar = lookup_variable_strcached(pInstr->pszName);
2506 if (pVar)
2507 {
2508 char const *pszExpandedVarValue = pVar->recursive ? recursively_expand(pVar) : pVar->value;
2509 pchDst = patsubst_expand_pat(pchDst,
2510 pszExpandedVarValue,
2511 pInstr->pszSearchPattern,
2512 pInstr->pszReplacePattern,
2513 &pInstr->pszSearchPattern[pInstr->offPctSearchPattern],
2514 &pInstr->pszReplacePattern[pInstr->offPctReplacePattern]);
2515 if (pVar->recursive)
2516 free((void *)pszExpandedVarValue);
2517 }
2518 else
2519 warn_undefined(pInstr->pszName, strcache2_get_len(&variable_strcache, pInstr->pszName));
2520
2521 pInstrCore = pInstr->pNext;
2522 break;
2523 }
2524
2525 case kKmkCcExpInstr_PlainFunction:
2526 {
2527 PKMKCCEXPPLAINFUNC pInstr = (PKMKCCEXPPLAINFUNC)pInstrCore;
2528 uint32_t iArg;
2529 if (!pInstr->FnCore.fDirty)
2530 {
2531#ifdef KMK_CC_STRICT
2532 uint32_t uCrcBefore = 0;
2533 uint32_t uCrcAfter = 0;
2534 iArg = pInstr->FnCore.cArgs;
2535 while (iArg-- > 0)
2536 uCrcBefore = kmk_cc_debug_string_hash(uCrcBefore, pInstr->apszArgs[iArg]);
2537#endif
2538
2539 pchDst = pInstr->FnCore.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->FnCore.pszFuncName);
2540
2541#ifdef KMK_CC_STRICT
2542 iArg = pInstr->FnCore.cArgs;
2543 while (iArg-- > 0)
2544 uCrcAfter = kmk_cc_debug_string_hash(uCrcAfter, pInstr->apszArgs[iArg]);
2545 KMK_CC_ASSERT(uCrcBefore == uCrcAfter);
2546#endif
2547 }
2548 else
2549 {
2550 char **papszShadowArgs = xmalloc((pInstr->FnCore.cArgs * 2 + 1) * sizeof(papszShadowArgs[0]));
2551 char **papszArgs = &papszShadowArgs[pInstr->FnCore.cArgs];
2552
2553 iArg = pInstr->FnCore.cArgs;
2554 papszArgs[iArg] = NULL;
2555 while (iArg-- > 0)
2556 papszArgs[iArg] = papszShadowArgs[iArg] = xstrdup(pInstr->apszArgs[iArg]);
2557
2558 pchDst = pInstr->FnCore.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->FnCore.pszFuncName);
2559
2560 iArg = pInstr->FnCore.cArgs;
2561 while (iArg-- > 0)
2562 free(papszShadowArgs[iArg]);
2563 free(papszShadowArgs);
2564 }
2565
2566 pInstrCore = pInstr->FnCore.pNext;
2567 break;
2568 }
2569
2570 case kKmkCcExpInstr_DynamicFunction:
2571 {
2572 PKMKCCEXPDYNFUNC pInstr = (PKMKCCEXPDYNFUNC)pInstrCore;
2573 char **papszArgsShadow = xmalloc( (pInstr->FnCore.cArgs * 2 + 1) * sizeof(char *));
2574 char **papszArgs = &papszArgsShadow[pInstr->FnCore.cArgs];
2575 uint32_t iArg;
2576
2577 if (!pInstr->FnCore.fDirty)
2578 {
2579#ifdef KMK_CC_STRICT
2580 uint32_t uCrcBefore = 0;
2581 uint32_t uCrcAfter = 0;
2582#endif
2583 iArg = pInstr->FnCore.cArgs;
2584 papszArgs[iArg] = NULL;
2585 while (iArg-- > 0)
2586 {
2587 char *pszArg;
2588 if (pInstr->aArgs[iArg].fSubprog)
2589 pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.Subprog, NULL);
2590 else
2591 pszArg = (char *)pInstr->aArgs[iArg].u.Plain.psz;
2592 papszArgsShadow[iArg] = pszArg;
2593 papszArgs[iArg] = pszArg;
2594#ifdef KMK_CC_STRICT
2595 uCrcBefore = kmk_cc_debug_string_hash(uCrcBefore, pszArg);
2596#endif
2597 }
2598 pchDst = pInstr->FnCore.pfnFunction(pchDst, papszArgs, pInstr->FnCore.pszFuncName);
2599
2600 iArg = pInstr->FnCore.cArgs;
2601 while (iArg-- > 0)
2602 {
2603#ifdef KMK_CC_STRICT
2604 KMK_CC_ASSERT(papszArgsShadow[iArg] == papszArgs[iArg]);
2605 uCrcAfter = kmk_cc_debug_string_hash(uCrcAfter, papszArgsShadow[iArg]);
2606#endif
2607 if (pInstr->aArgs[iArg].fSubprog)
2608 free(papszArgsShadow[iArg]);
2609 }
2610 KMK_CC_ASSERT(uCrcBefore == uCrcAfter);
2611 }
2612 else
2613 {
2614 iArg = pInstr->FnCore.cArgs;
2615 papszArgs[iArg] = NULL;
2616 while (iArg-- > 0)
2617 {
2618 char *pszArg;
2619 if (pInstr->aArgs[iArg].fSubprog)
2620 pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.Subprog, NULL);
2621 else
2622 pszArg = xstrdup(pInstr->aArgs[iArg].u.Plain.psz);
2623 papszArgsShadow[iArg] = pszArg;
2624 papszArgs[iArg] = pszArg;
2625 }
2626
2627 pchDst = pInstr->FnCore.pfnFunction(pchDst, papszArgs, pInstr->FnCore.pszFuncName);
2628
2629 iArg = pInstr->FnCore.cArgs;
2630 while (iArg-- > 0)
2631 free(papszArgsShadow[iArg]);
2632 }
2633 free(papszArgsShadow);
2634
2635 pInstrCore = pInstr->FnCore.pNext;
2636 break;
2637 }
2638
2639 case kKmkCcExpInstr_Jump:
2640 {
2641 PKMKCCEXPJUMP pInstr = (PKMKCCEXPJUMP)pInstrCore;
2642 pInstrCore = pInstr->pNext;
2643 break;
2644 }
2645
2646 case kKmkCcExpInstr_Return:
2647 return pchDst;
2648
2649 default:
2650 fatal(NULL, _("Unknown string expansion opcode: %d (%#x)"),
2651 (int)pInstrCore->enmOpCode, (int)pInstrCore->enmOpCode);
2652 return NULL;
2653 }
2654 }
2655}
2656
2657
2658/**
2659 * Updates the string expansion statistics.
2660 *
2661 * @param pStats The statistics structure to update.
2662 * @param cchResult The result lenght.
2663 */
2664void kmk_cc_exp_stats_update(PKMKCCEXPSTATS pStats, uint32_t cchResult)
2665{
2666 /*
2667 * The average is simplified and not an exact average for every
2668 * expansion that has taken place.
2669 */
2670 pStats->cchAvg = (pStats->cchAvg * 7 + cchResult) / 8;
2671}
2672
2673
2674/**
2675 * Execute a string expansion subprogram, outputting to a new heap buffer.
2676 *
2677 * @returns Pointer to the output buffer (hand to free when done).
2678 * @param pSubprog The subprogram to execute.
2679 * @param pcchResult Where to return the size of the result. Optional.
2680 */
2681static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubprog, uint32_t *pcchResult)
2682{
2683 char *pchOldVarBuf;
2684 unsigned int cbOldVarBuf;
2685 char *pchDst;
2686 char *pszResult;
2687 uint32_t cchResult;
2688
2689 /*
2690 * Temporarily replace the variable buffer while executing the instruction
2691 * stream for this subprogram.
2692 */
2693 pchDst = install_variable_buffer_with_hint(&pchOldVarBuf, &cbOldVarBuf,
2694 pSubprog->Stats.cchAvg ? pSubprog->Stats.cchAvg + 32 : 256);
2695
2696 pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pSubprog->pFirstInstr, pchDst);
2697
2698 /* Ensure that it's terminated. */
2699 pchDst = variable_buffer_output(pchDst, "\0", 1) - 1;
2700
2701 /* Grab the result buffer before restoring the previous one. */
2702 pszResult = variable_buffer;
2703 cchResult = (uint32_t)(pchDst - pszResult);
2704 if (pcchResult)
2705 *pcchResult = cchResult;
2706 kmk_cc_exp_stats_update(&pSubprog->Stats, cchResult);
2707
2708 variable_buffer = pchOldVarBuf;
2709 variable_buffer_length = cbOldVarBuf;
2710
2711 return pszResult;
2712}
2713
2714
2715/**
2716 * Execute a string expansion program, outputting to the current variable
2717 * buffer.
2718 *
2719 * @returns New variable buffer position.
2720 * @param pProg The program to execute.
2721 * @param pchDst The current varaible buffer position.
2722 */
2723static char *kmk_exec_expand_prog_to_var_buf(PKMKCCEXPPROG pProg, char *pchDst)
2724{
2725 uint32_t cchResult;
2726 uint32_t offStart = (uint32_t)(pchDst - variable_buffer);
2727
2728 if (pProg->Stats.cchAvg >= variable_buffer_length - offStart)
2729 pchDst = ensure_variable_buffer_space(pchDst, offStart + pProg->Stats.cchAvg + 32);
2730
2731 KMK_CC_ASSERT(pProg->cRefs > 0);
2732 pProg->cRefs++;
2733
2734 pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pProg->pFirstInstr, pchDst);
2735
2736 pProg->cRefs--;
2737 KMK_CC_ASSERT(pProg->cRefs > 0);
2738
2739 cchResult = (uint32_t)(pchDst - variable_buffer);
2740 KMK_CC_ASSERT(cchResult >= offStart);
2741 cchResult -= offStart;
2742 kmk_cc_exp_stats_update(&pProg->Stats, cchResult);
2743 g_cVarForExpandExecs++;
2744
2745 return pchDst;
2746}
2747
2748
2749/**
2750 * Expands a variable into a variable buffer using its expandprog.
2751 *
2752 * @returns The new variable buffer position.
2753 * @param pVar Pointer to the variable. Must have a program.
2754 * @param pchDst Pointer to the current variable buffer position.
2755 */
2756char *kmk_exec_expand_to_var_buf(struct variable *pVar, char *pchDst)
2757{
2758 KMK_CC_ASSERT(pVar->expandprog);
2759 KMK_CC_ASSERT(pVar->expandprog->uInputHash == kmk_cc_debug_string_hash(0, pVar->value));
2760 return kmk_exec_expand_prog_to_var_buf(pVar->expandprog, pchDst);
2761}
2762
2763
2764
2765
2766
2767/*
2768 *
2769 * Makefile evaluation programs.
2770 * Makefile evaluation programs.
2771 * Makefile evaluation programs.
2772 *
2773 */
2774
2775static size_t kmk_cc_eval_detect_eol_style(char *pchFirst, char *pchSecond, const char *pszContent, size_t cchContent)
2776{
2777 /* Look for LF first. */
2778 const char *pszTmp = (const char *)memchr(pszContent, '\n', cchContent);
2779 if (pszTmp)
2780 {
2781 /* CRLF? */
2782 if (pszTmp != pszContent && pszTmp[-1] == '\r')
2783 {
2784 *pchFirst = '\r';
2785 *pchSecond = '\n';
2786 return 2;
2787 }
2788
2789 /* No, LF or LFCR. (pszContent is zero terminated, so no bounds checking necessary.) */
2790 *pchFirst = '\n';
2791 if (pszTmp[1] != '\r')
2792 {
2793 *pchSecond = 0;
2794 return 1;
2795 }
2796 *pchSecond = '\r';
2797 return 2;
2798 }
2799
2800 /* Probably no EOLs here. */
2801 if (memchr(pszContent, '\r', cchContent) == NULL)
2802 {
2803 *pchSecond = *pchFirst = 0;
2804 return 0;
2805 }
2806
2807 /* kind of unlikely */
2808 *pchFirst = '\r';
2809 *pchSecond = 0;
2810 return 1;
2811}
2812
2813
2814#if 0
2815/**
2816 * Checks whether we've got an EOL escape sequence or not.
2817 *
2818 * @returns non-zero if escaped EOL, 0 if not (i.e. actual EOL).
2819 * @param pszContent The string pointer @a offEol is relative to.
2820 * @param offEol The offset of the first EOL char.
2821 */
2822static unsigned kmk_cc_eval_is_eol_escape_seq(const char *pszContent, size_t offEol)
2823{
2824 /* The caller has already checked out two backslashes. */
2825 size_t offFirstBackslash = offEol;
2826 KMK_CC_ASSERT(offFirstBackslash >= 2);
2827 offFirstBackslash -= 2;
2828
2829 /* Find the first backslash. */
2830 while (offFirstBackslash > 0 && pszContent[offFirstBackslash - 1] == '\\')
2831 offFirstBackslash--;
2832
2833 /* Odd number -> escaped EOL; Even number -> real EOL; */
2834 return (offEol - offFirstBackslash) & 1;
2835}
2836#endif
2837
2838
2839
2840typedef enum kmk_cc_eval_token
2841{
2842 /** Invalid token . */
2843 kKmkCcEvalToken_Invalid = 0,
2844
2845 /** Assignment: '=' */
2846 kKmkCcEvalToken_AssignRecursive,
2847 /** Assignment: ':=' */
2848 kKmkCcEvalToken_AssignSimple,
2849 /** Assignment: '+=' */
2850 kKmkCcEvalToken_AssignAppend,
2851 /** Assignment: '<=' */
2852 kKmkCcEvalToken_AssignPrepend,
2853 /** Assignment: '?=' */
2854 kKmkCcEvalToken_AssignIfNew,
2855 /** Assignment: 'define' */
2856 kKmkCcEvalToken_define,
2857 /** Unassignment: 'undefine' */
2858 kKmkCcEvalToken_undefine,
2859
2860 /* Assignment modifier: 'local' */
2861 kKmkCcEvalToken_local,
2862 /* Assignment modifier: 'override' */
2863 kKmkCcEvalToken_override,
2864 /* Assignment modifier: 'private' (target variable not inh by deps) */
2865 kKmkCcEvalToken_private,
2866 /* Assignment modifier / other variable thing: 'export' */
2867 kKmkCcEvalToken_export,
2868 /* Other variable thing: 'unexport' */
2869 kKmkCcEvalToken_unexport,
2870
2871 kKmkCcEvalToken_ifdef,
2872 kKmkCcEvalToken_ifndef,
2873 kKmkCcEvalToken_ifeq,
2874 kKmkCcEvalToken_ifneq,
2875 kKmkCcEvalToken_if1of,
2876 kKmkCcEvalToken_ifn1of,
2877 kKmkCcEvalToken_if,
2878 kKmkCcEvalToken_else,
2879 kKmkCcEvalToken_endif,
2880
2881 kKmkCcEvalToken_include,
2882 kKmkCcEvalToken_include_silent,
2883 kKmkCcEvalToken_includedep,
2884 kKmkCcEvalToken_includedep_queue,
2885 kKmkCcEvalToken_includedep_flush,
2886
2887 kKmkCcEvalToken_colon,
2888 kKmkCcEvalToken_double_colon,
2889 kKmkCcEvalToken_plus,
2890 kKmkCcEvalToken_plus_maybe,
2891
2892 kKmkCcEvalToken_vpath,
2893
2894 /** Plain word. */
2895 kKmkCcEvalToken_WordPlain,
2896 /** Word that maybe in need of expanding. */
2897 kKmkCcEvalToken_WordWithDollar,
2898
2899 kKmkCcEvalToken_End
2900} KMKCCEVALTOKEN;
2901
2902/**
2903 * A tokenized word.
2904 */
2905typedef struct kmk_cc_eval_word
2906{
2907 /** The token word (lexeme). */
2908 const char *pszWord;
2909 /** The length of the word (lexeme). */
2910 uint32_t cchWord;
2911 /** The token classification. */
2912 KMKCCEVALTOKEN enmToken;
2913} KMKCCEVALWORD;
2914typedef KMKCCEVALWORD *PKMKCCEVALWORD;
2915
2916
2917/**
2918 * Escaped end-of-line sequence in the current line.
2919 */
2920typedef struct KMKCCEVALESCEOL
2921{
2922 /** Offset at which the EOL escape sequence starts for a non-command line. */
2923 size_t offEsc;
2924 /** Offset of the newline sequence. */
2925 size_t offEol;
2926} KMKCCEVALESCEOL;
2927typedef KMKCCEVALESCEOL *PKMKCCEVALESCEOL;
2928
2929
2930/**
2931 * String copy segment.
2932 */
2933typedef struct KMKCCEVALSTRCPYSEG
2934{
2935 /** The start. */
2936 const char *pchSrc;
2937 /** The number of chars to copy and whether to prepend space.
2938 * Negative values indicates that we should prepend a space. */
2939 ssize_t cchSrcAndPrependSpace;
2940} KMKCCEVALSTRCPYSEG;
2941typedef KMKCCEVALSTRCPYSEG *PKMKCCEVALSTRCPYSEG;
2942typedef KMKCCEVALSTRCPYSEG const *PCKMKCCEVALSTRCPYSEG;
2943
2944
2945typedef struct KMKCCEVALCOMPILER
2946{
2947 /** Pointer to the KMKCCEVALPROG::pBlockTail member. */
2948 PKMKCCBLOCK *ppBlockTail;
2949
2950 /** @name Line parsing state.
2951 * @{ */
2952 /** Offset of newline escape sequences in the current line.
2953 * This is only applicable if cEscEols is not zero. */
2954 PKMKCCEVALESCEOL paEscEols;
2955 /** The number of number of paEscEols entries we've allocated. */
2956 unsigned cEscEolsAllocated;
2957 /** Number of escaped EOLs (line count - 1). */
2958 unsigned cEscEols;
2959 /** The paEscEols entry corresponding to the current parsing location.
2960 * Still to be seen how accurate this can be made to be. */
2961 unsigned iEscEol;
2962
2963 /** The current line number (for error handling / debugging). */
2964 unsigned iLine;
2965 /** The start offset of the current line. */
2966 size_t offLine;
2967 /** Length of the current line, sans the final EOL and comments. */
2968 size_t cchLine;
2969 /** Length of the current line, sans the final EOL but with comments. */
2970 size_t cchLineWithComments;
2971
2972 /** The first char in an EOL sequence.
2973 * We ASSUMES that this char won't appear in any other sequence in the file,
2974 * thus skipping matching any subsequent chars. */
2975 char chFirstEol;
2976 /** The second char in an EOL sequence, if applicable. */
2977 char chSecondEol;
2978
2979 /** The length of the EOL sequence. */
2980 size_t cchEolSeq;
2981 /** The minimum length of an esacped EOL sequence (cchEolSeq + 1). */
2982 size_t cchEscEolSeq;
2983
2984 /** String copy segments. */
2985 PKMKCCEVALSTRCPYSEG paStrCopySegs;
2986 /** The number of segments that has been prepared. */
2987 unsigned cStrCopySegs;
2988 /** The number of segments we've allocated. */
2989 unsigned cStrCopySegsAllocated;
2990 /** @} */
2991
2992
2993 /** @name Recipe state.
2994 * @{ */
2995 /** Set if we're working on a recipe. */
2996 PKMKCCEVALRECIPE pRecipe;
2997 /** Set for ignoring recipes without targets (Sun OS 4 Make). */
2998 uint8_t fNoTargetRecipe;
2999 /** The command prefix character. */
3000 char chCmdPrefix;
3001 /** @} */
3002
3003 /** @name Tokenzied words.
3004 * @{ */
3005 uint32_t cWords;
3006 uint32_t cWordsAllocated;
3007 PKMKCCEVALWORD paWords;
3008 /** @} */
3009
3010 /** @name Conditionals.
3011 * @{ */
3012 /** Current conditional stack depth. */
3013 unsigned cIfs;
3014 /** The conditional directive stack. */
3015 PKMKCCEVALIFCORE apIfs[KMK_CC_EVAL_MAX_IF_DEPTH];
3016 /** @} */
3017
3018 /** The program being compiled. */
3019 PKMKCCEVALPROG pEvalProg;
3020 /** Pointer to the content. */
3021 const char *pszContent;
3022 /** The amount of input to parse. */
3023 size_t cchContent;
3024} KMKCCEVALCOMPILER;
3025typedef KMKCCEVALCOMPILER *PKMKCCEVALCOMPILER;
3026
3027
3028static void kmk_cc_eval_init_compiler(PKMKCCEVALCOMPILER pCompiler, PKMKCCEVALPROG pEvalProg, unsigned iLine,
3029 const char *pszContent, size_t cchContent)
3030{
3031 pCompiler->ppBlockTail = &pEvalProg->pBlockTail;
3032
3033 pCompiler->pRecipe = NULL;
3034 pCompiler->fNoTargetRecipe = 0;
3035 pCompiler->chCmdPrefix = cmd_prefix;
3036
3037 pCompiler->cWordsAllocated = 0;
3038 pCompiler->paWords = NULL;
3039
3040 pCompiler->cEscEolsAllocated = 0;
3041 pCompiler->paEscEols = NULL;
3042 pCompiler->iLine = iLine;
3043
3044 pCompiler->cIfs = 0;
3045
3046 pCompiler->pEvalProg = pEvalProg;
3047 pCompiler->pszContent = pszContent;
3048 pCompiler->cchContent = cchContent;
3049
3050 /* Detect EOL style. */
3051 pCompiler->cchEolSeq = kmk_cc_eval_detect_eol_style(&pCompiler->chFirstEol, &pCompiler->chSecondEol,
3052 pszContent, cchContent);
3053 pCompiler->cchEscEolSeq = 1 + pCompiler->cchEolSeq;
3054}
3055
3056
3057static void kmk_cc_eval_delete_compiler(PKMKCCEVALCOMPILER pCompiler)
3058{
3059 if (pCompiler->paWords)
3060 free(pCompiler->paWords);
3061 if (pCompiler->paEscEols)
3062 free(pCompiler->paEscEols);
3063}
3064
3065static void kmk_cc_eval_fatal(PKMKCCEVALCOMPILER pCompiler, const char *pchWhere, const char *pszMsg, ...)
3066{
3067 va_list va;
3068 unsigned iLine = pCompiler->iLine;
3069
3070 log_working_directory(1);
3071
3072 /*
3073 * If we have a pointer location, use it to figure out the exact line and column.
3074 */
3075 if (pchWhere)
3076 {
3077 size_t offLine = pCompiler->offLine;
3078 size_t off = pchWhere - pCompiler->pszContent;
3079 unsigned i = 0;
3080 while ( i < pCompiler->cEscEols
3081 && off > pCompiler->paEscEols[i].offEol)
3082 {
3083 offLine = pCompiler->paEscEols[i].offEol + 1 + pCompiler->cchEolSeq;
3084 iLine++;
3085 i++;
3086 }
3087 KMK_CC_ASSERT(off <= pCompiler->cchContent);
3088
3089 if (pCompiler->pEvalProg->pszVarName)
3090 fprintf(stderr, "%s:%u:%u: *** fatal parsing error in %s: ",
3091 pCompiler->pEvalProg->pszFilename, iLine, (unsigned)(off - offLine), pCompiler->pEvalProg->pszVarName);
3092 else
3093 fprintf(stderr, "%s:%u:%u: *** fatal parsing error: ",
3094 pCompiler->pEvalProg->pszFilename, iLine, (unsigned)(off - offLine));
3095 }
3096 else if (pCompiler->pEvalProg->pszVarName)
3097 fprintf(stderr, "%s:%u: *** fatal parsing error in %s: ",
3098 pCompiler->pEvalProg->pszFilename, iLine, pCompiler->pEvalProg->pszVarName);
3099 else
3100 fprintf(stderr, "%s:%u: *** fatal parsing error: ",
3101 pCompiler->pEvalProg->pszFilename, iLine);
3102
3103 /*
3104 * Print the message and die.
3105 */
3106 va_start(va, pszMsg);
3107 vfprintf(stderr, pszMsg, va);
3108 va_end(va);
3109 fputs(". Stop.\n", stderr);
3110
3111 for (;;)
3112 die(2);
3113}
3114
3115
3116static void kmk_cc_eval_fatal_eol(PKMKCCEVALCOMPILER pCompiler, const char *pchEol, unsigned iLine, size_t offLine)
3117{
3118 pCompiler->iLine = iLine;
3119 pCompiler->offLine = offLine;
3120
3121 for (;;)
3122 kmk_cc_eval_fatal(pCompiler, pchEol, "Missing 2nd EOL character: found %#x instead of %#x\n",
3123 pchEol, pCompiler->chSecondEol);
3124}
3125
3126
3127/**
3128 * Compiles a string expansion subprogram.
3129 *
3130 * @param pCompiler The compiler state.
3131 * @param pszExpr The expression to compile.
3132 * @param cchExpr The length of the expression.
3133 * @param pSubprog The subprogram to compile.
3134 */
3135static void kmk_cc_eval_compile_string_exp_subprog(PKMKCCEVALCOMPILER pCompiler, const char *pszExpr, size_t cchExpr,
3136 PKMKCCEXPSUBPROG pSubprog)
3137{
3138 int rc = kmk_cc_exp_compile_subprog(pCompiler->ppBlockTail, pszExpr, cchExpr, pSubprog);
3139 if (rc == 0)
3140 return;
3141 kmk_cc_eval_fatal(pCompiler, NULL, "String expansion compile error");
3142}
3143
3144
3145/** @name KMK_CC_WORD_COMP_CONST_XXX - Optimal(/insane) constant work matching.
3146 * @{
3147 */
3148#if defined(KBUILD_ARCH_X86) || defined(KBUILD_ARCH_AMD64) /* Unaligned access is reasonably cheap. */
3149# define KMK_CC_WORD_COMP_CONST_2(a_pchLine, a_pszWord) \
3150 ( *(uint16_t const *)(a_pchLine) == *(uint16_t const *)(a_pszWord) )
3151# define KMK_CC_WORD_COMP_CONST_3(a_pchLine, a_pszWord) \
3152 ( *(uint16_t const *)(a_pchLine) == *(uint16_t const *)(a_pszWord) \
3153 && (a_pchLine)[2] == (a_pszWord)[2] )
3154# define KMK_CC_WORD_COMP_CONST_4(a_pchLine, a_pszWord) \
3155 ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) )
3156# define KMK_CC_WORD_COMP_CONST_5(a_pchLine, a_pszWord) \
3157 ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) \
3158 && (a_pchLine)[4] == (a_pszWord)[4] )
3159# define KMK_CC_WORD_COMP_CONST_6(a_pchLine, a_pszWord) \
3160 ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) \
3161 && ((uint16_t const *)(a_pchLine))[2] == ((uint32_t const *)(a_pszWord))[2] )
3162# define KMK_CC_WORD_COMP_CONST_7(a_pchLine, a_pszWord) \
3163 ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) \
3164 && ((uint16_t const *)(a_pchLine))[2] == ((uint32_t const *)(a_pszWord))[2] \
3165 && (a_pchLine)[6] == (a_pszWord)[6] )
3166# define KMK_CC_WORD_COMP_CONST_8(a_pchLine, a_pszWord) \
3167 ( *(uint64_t const *)(a_pchLine) == *(uint64_t const *)(a_pszWord) )
3168# define KMK_CC_WORD_COMP_CONST_10(a_pchLine, a_pszWord) \
3169 ( *(uint64_t const *)(a_pchLine) == *(uint64_t const *)(a_pszWord) \
3170 && ((uint16_t const *)(a_pchLine))[4] == ((uint16_t const *)(a_pszWord))[4] )
3171# define KMK_CC_WORD_COMP_CONST_16(a_pchLine, a_pszWord) \
3172 ( *(uint64_t const *)(a_pchLine) == *(uint64_t const *)(a_pszWord) \
3173 && ((uint64_t const *)(a_pchLine))[1] == ((uint64_t const *)(a_pszWord))[1] )
3174#else
3175# define KMK_CC_WORD_COMP_CONST_2(a_pchLine, a_pszWord) \
3176 ( (a_pchLine)[0] == (a_pszWord)[0] \
3177 && (a_pchLine)[1] == (a_pszWord)[1] )
3178# define KMK_CC_WORD_COMP_CONST_3(a_pchLine, a_pszWord) \
3179 ( (a_pchLine)[0] == (a_pszWord)[0] \
3180 && (a_pchLine)[1] == (a_pszWord)[1] \
3181 && (a_pchLine)[2] == (a_pszWord)[2] )
3182# define KMK_CC_WORD_COMP_CONST_4(a_pchLine, a_pszWord) \
3183 ( (a_pchLine)[0] == (a_pszWord)[0] \
3184 && (a_pchLine)[1] == (a_pszWord)[1] \
3185 && (a_pchLine)[2] == (a_pszWord)[2] \
3186 && (a_pchLine)[3] == (a_pszWord)[3] )
3187# define KMK_CC_WORD_COMP_CONST_5(a_pchLine, a_pszWord) \
3188 ( (a_pchLine)[0] == (a_pszWord)[0] \
3189 && (a_pchLine)[1] == (a_pszWord)[1] \
3190 && (a_pchLine)[2] == (a_pszWord)[2] \
3191 && (a_pchLine)[3] == (a_pszWord)[3] \
3192 && (a_pchLine)[4] == (a_pszWord)[4] )
3193# define KMK_CC_WORD_COMP_CONST_6(a_pchLine, a_pszWord) \
3194 ( (a_pchLine)[0] == (a_pszWord)[0] \
3195 && (a_pchLine)[1] == (a_pszWord)[1] \
3196 && (a_pchLine)[2] == (a_pszWord)[2] \
3197 && (a_pchLine)[3] == (a_pszWord)[3] \
3198 && (a_pchLine)[4] == (a_pszWord)[4] \
3199 && (a_pchLine)[5] == (a_pszWord)[5] )
3200# define KMK_CC_WORD_COMP_CONST_7(a_pchLine, a_pszWord) \
3201 ( (a_pchLine)[0] == (a_pszWord)[0] \
3202 && (a_pchLine)[1] == (a_pszWord)[1] \
3203 && (a_pchLine)[2] == (a_pszWord)[2] \
3204 && (a_pchLine)[3] == (a_pszWord)[3] \
3205 && (a_pchLine)[4] == (a_pszWord)[4] \
3206 && (a_pchLine)[5] == (a_pszWord)[5] \
3207 && (a_pchLine)[6] == (a_pszWord)[6] )
3208# define KMK_CC_WORD_COMP_CONST_8(a_pchLine, a_pszWord) \
3209 ( (a_pchLine)[0] == (a_pszWord)[0] \
3210 && (a_pchLine)[1] == (a_pszWord)[1] \
3211 && (a_pchLine)[2] == (a_pszWord)[2] \
3212 && (a_pchLine)[3] == (a_pszWord)[3] \
3213 && (a_pchLine)[4] == (a_pszWord)[4] \
3214 && (a_pchLine)[5] == (a_pszWord)[5] \
3215 && (a_pchLine)[6] == (a_pszWord)[6] \
3216 && (a_pchLine)[7] == (a_pszWord)[7] )
3217# define KMK_CC_WORD_COMP_CONST_10(a_pchLine, a_pszWord) \
3218 ( (a_pchLine)[0] == (a_pszWord)[0] \
3219 && (a_pchLine)[1] == (a_pszWord)[1] \
3220 && (a_pchLine)[2] == (a_pszWord)[2] \
3221 && (a_pchLine)[3] == (a_pszWord)[3] \
3222 && (a_pchLine)[4] == (a_pszWord)[4] \
3223 && (a_pchLine)[5] == (a_pszWord)[5] \
3224 && (a_pchLine)[6] == (a_pszWord)[6] \
3225 && (a_pchLine)[7] == (a_pszWord)[7] \
3226 && (a_pchLine)[8] == (a_pszWord)[8] \
3227 && (a_pchLine)[9] == (a_pszWord)[9] )
3228# define KMK_CC_WORD_COMP_CONST_16(a_pchLine, a_pszWord) \
3229 ( (a_pchLine)[0] == (a_pszWord)[0] \
3230 && (a_pchLine)[1] == (a_pszWord)[1] \
3231 && (a_pchLine)[2] == (a_pszWord)[2] \
3232 && (a_pchLine)[3] == (a_pszWord)[3] \
3233 && (a_pchLine)[4] == (a_pszWord)[4] \
3234 && (a_pchLine)[5] == (a_pszWord)[5] \
3235 && (a_pchLine)[6] == (a_pszWord)[6] \
3236 && (a_pchLine)[7] == (a_pszWord)[7] \
3237 && (a_pchLine)[8] == (a_pszWord)[8] \
3238 && (a_pchLine)[9] == (a_pszWord)[9] \
3239 && (a_pchLine)[10] == (a_pszWord)[10] \
3240 && (a_pchLine)[11] == (a_pszWord)[11] \
3241 && (a_pchLine)[12] == (a_pszWord)[12] \
3242 && (a_pchLine)[13] == (a_pszWord)[13] \
3243 && (a_pchLine)[14] == (a_pszWord)[14] \
3244 && (a_pchLine)[15] == (a_pszWord)[15])
3245#endif
3246/** See if a starting of a given length starts with a constant word. */
3247#define KMK_CC_WORD_COMP_IS_EOL(a_pCompiler, a_pchLine, a_cchLine) \
3248 ( (a_cchLine) == 0 \
3249 || KMK_CC_EVAL_IS_SPACE((a_pchLine)[0]) \
3250 || ((a_pchLine)[0] == '\\' && (a_pchLine)[1] == (a_pCompiler)->chFirstEol) ) \
3251
3252/** See if a starting of a given length starts with a constant word. */
3253#define KMK_CC_WORD_COMP_CONST(a_pCompiler, a_pchLine, a_cchLine, a_pszWord, a_cchWord) \
3254 ( (a_cchLine) >= (a_cchWord) \
3255 && ( (a_cchLine) == (a_cchWord) \
3256 || KMK_CC_EVAL_IS_SPACE((a_pchLine)[a_cchWord]) \
3257 || ((a_pchLine)[a_cchWord] == '\\' && (a_pchLine)[(a_cchWord) + 1] == (a_pCompiler)->chFirstEol) ) \
3258 && KMK_CC_WORD_COMP_CONST_##a_cchWord(a_pchLine, a_pszWord) )
3259/** @} */
3260
3261
3262/**
3263 * Checks if a_ch is a space after a word.
3264 *
3265 * Since there is always a terminating zero, the user can safely access a char
3266 * beyond @a a_cchLeft. However, that byte isn't necessarily a zero terminator
3267 * character, so we have to check @a a_cchLeft whether we're at the end of the
3268 * parsing input string.
3269 *
3270 * @returns true / false.
3271 * @param a_pCompiler The compiler instance data.
3272 * @param a_ch The character to inspect.
3273 * @param a_ch2 The character following it, in case of escaped EOL.
3274 * @param a_cchLeft The number of chars left to parse (from @a a_ch).
3275 */
3276#define KMK_CC_EVAL_IS_SPACE_AFTER_WORD(a_pCompiler, a_ch, a_ch2, a_cchLeft) \
3277 ( a_cchLeft == 0 \
3278 || KMK_CC_EVAL_IS_SPACE(a_ch) \
3279 || ((a_ch) == '\\' && (a_ch2) == (a_pCompiler)->chFirstEol) )
3280
3281/**
3282 * Used to skip spaces after a word.
3283 *
3284 * We ASSUME that the first char is a space or that we've reached the end of the
3285 * string (a_cchLeft == 0).
3286 *
3287 * @param a_pCompiler The compiler instance data.
3288 * @param a_pchWord The current input position, this will be moved to
3289 * the start of the next word or end of the input.
3290 * @param a_cchLeft The number of chars left to parse. This will be
3291 * updated.
3292 */
3293#define KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(a_pCompiler, a_pchWord, a_cchLeft) \
3294 do { \
3295 /* Skip the first char which is known to be a space, end of line or end of input. */ \
3296 if ((a_cchLeft) > 0) \
3297 { \
3298 char const chSkipBlanksFirst = *(a_pchWord); \
3299 KMK_CC_ASSERT(KMK_CC_EVAL_IS_SPACE_AFTER_WORD(a_pCompiler, chSkipBlanksFirst, (a_pchWord)[1], a_cchLeft)); \
3300 if (chSkipBlanksFirst != '\\') \
3301 { \
3302 (a_pchWord) += 1; \
3303 (a_cchLeft) -= 1; \
3304 \
3305 /* Another space or escaped EOL? Then there are probably more then, so call worker function. */ \
3306 if ((a_cchLeft) > 0) \
3307 { \
3308 char const chSkipBlanksSecond = *(a_pchWord); \
3309 if (KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(chSkipBlanksSecond)) \
3310 (a_pchWord) = kmk_cc_eval_skip_spaces_after_word_slow(a_pchWord, &(a_cchLeft), \
3311 chSkipBlanksSecond, a_pCompiler); \
3312 } \
3313 } \
3314 else /* escape sequences can be complicated. */ \
3315 (a_pchWord) = kmk_cc_eval_skip_spaces_after_word_slow(a_pchWord, &(a_cchLeft), \
3316 chSkipBlanksFirst, a_pCompiler); \
3317 } \
3318 } while (0)
3319
3320
3321//static int kmk_cc_eval_skip_esc_eol_slow(const char *pchWord, size_t cchLeft, PKMKCCEVALCOMPILER pCompiler,
3322// const char **ppchWord, size_t *pcchLeft)
3323//{
3324// KMK_CC_ASSERT(pchWord[0] == '\\');
3325// if (pCompiler->cEscEols)
3326// {
3327// size_t cchMin = 1 + pCompiler->chFirstEol;
3328// if (cchLeft >= cchMin)
3329// {
3330// /* The simple case, no extra backslashes. */
3331// if (pchWord[1] == pCompiler->chFirstEol)
3332// {
3333// *pcchLeft = cchLeft - cchMin;
3334// *pchWord = pchWord + cchMin;
3335// return 1;
3336// }
3337//
3338// /* The unlikly case, */
3339//
3340// }
3341// }
3342// return 0;
3343//}
3344
3345
3346/**
3347 * The slow path of KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD.
3348 *
3349 * This is called to handles escaped EOL sequences, as these can involve
3350 * multiple backslashes and therefore doesn't led themselves well to inlined
3351 * code.
3352 *
3353 * The other case this is used for is to handle more than once space, since it's
3354 * likely that when there are two there might be more. No point in inlining
3355 * that, better do some loop unrolling instead.
3356 *
3357 * @returns Points to the first non-space character or end of input.
3358 * @param pchWord The current position. There is some kind of char
3359 * @param pcchLeft Pointer to the cchLeft variable, this is both
3360 * input and output.
3361 * @param ch The current character.
3362 * @param pCompiler The compiler instance data.
3363 */
3364static const char *kmk_cc_eval_skip_spaces_after_word_slow(const char *pchWord, size_t *pcchLeft, char ch,
3365 PKMKCCEVALCOMPILER pCompiler)
3366{
3367 size_t cchLeft = *pcchLeft;
3368
3369 /*
3370 * Skip the pending space or EOL found by the caller. We need to
3371 * confirm the EOL.
3372 *
3373 * Note! We only need to care about simple backslash+EOL sequences here
3374 * since we're either at the end of a validated word, or we've already
3375 * skipped one space. In the former case, someone else has already
3376 * validated the escape esequence, in the latter case multiple
3377 * backslashes would indicate a new word that that we should return.
3378 */
3379 if (ch != '\\')
3380 {
3381 pchWord += 1;
3382 cchLeft -= 1;
3383 }
3384 else if ( cchLeft >= pCompiler->cchEscEolSeq
3385 && pchWord[1] == pCompiler->chFirstEol)
3386 {
3387 KMK_CC_ASSERT(pCompiler->cchEolSeq == 1 || pchWord[2] == pCompiler->chSecondEol);
3388 pchWord += pCompiler->cchEscEolSeq;
3389 cchLeft -= pCompiler->cchEscEolSeq;
3390 pCompiler->iEscEol++;
3391 }
3392 else
3393 return pchWord;
3394
3395 /*
3396 * Skip further spaces. We unrolls 4 loops here.
3397 * ASSUMES cchEscEolSeq is either 2 or 3!
3398 */
3399 KMK_CC_ASSERT(pCompiler->cchEscEolSeq == 2 || pCompiler->cchEscEolSeq == 3);
3400 while (cchLeft >= 4)
3401 {
3402 /* First char. */
3403 ch = pchWord[0];
3404 if (KMK_CC_EVAL_IS_SPACE(ch))
3405 { /* maybe likely */ }
3406 else if ( ch == '\\'
3407 && pchWord[1] == pCompiler->chFirstEol)
3408 {
3409 pchWord += pCompiler->cchEscEolSeq;
3410 cchLeft -= pCompiler->cchEscEolSeq;
3411 pCompiler->iEscEol++;
3412 continue;
3413 }
3414 else
3415 {
3416 *pcchLeft = cchLeft;
3417 return pchWord;
3418 }
3419
3420 /* Second char. */
3421 ch = pchWord[1];
3422 if (KMK_CC_EVAL_IS_SPACE(ch))
3423 { /* maybe likely */ }
3424 else if ( ch == '\\'
3425 && pchWord[2] == pCompiler->chFirstEol)
3426 {
3427 pchWord += 1 + pCompiler->cchEscEolSeq;
3428 cchLeft -= 1 + pCompiler->cchEscEolSeq;
3429 pCompiler->iEscEol++;
3430 continue;
3431 }
3432 else
3433 {
3434 *pcchLeft = cchLeft - 1;
3435 return pchWord + 1;
3436 }
3437
3438 /* Third char. */
3439 ch = pchWord[2];
3440 if (KMK_CC_EVAL_IS_SPACE(ch))
3441 { /* maybe likely */ }
3442 else if ( ch == '\\'
3443 && pchWord[3] == pCompiler->chFirstEol
3444 && cchLeft >= 2 + pCompiler->cchEscEolSeq)
3445 {
3446 pchWord += 2 + pCompiler->cchEscEolSeq;
3447 cchLeft -= 2 + pCompiler->cchEscEolSeq;
3448 pCompiler->iEscEol++;
3449 continue;
3450 }
3451 else
3452 {
3453 *pcchLeft = cchLeft - 2;
3454 return pchWord + 2;
3455 }
3456
3457 /* Third char. */
3458 ch = pchWord[3];
3459 if (KMK_CC_EVAL_IS_SPACE(ch))
3460 {
3461 pchWord += 4;
3462 cchLeft -= 4;
3463 }
3464 else if ( ch == '\\'
3465 && cchLeft >= 3 + pCompiler->cchEscEolSeq
3466 && pchWord[4] == pCompiler->chFirstEol)
3467 {
3468 pchWord += 3 + pCompiler->cchEscEolSeq;
3469 cchLeft -= 3 + pCompiler->cchEscEolSeq;
3470 pCompiler->iEscEol++;
3471 }
3472 else
3473 {
3474 *pcchLeft = cchLeft - 3;
3475 return pchWord + 3;
3476 }
3477 }
3478
3479 /*
3480 * Simple loop for the final three chars.
3481 */
3482 while (cchLeft > 0)
3483 {
3484 /* First char. */
3485 ch = *pchWord;
3486 if (KMK_CC_EVAL_IS_SPACE(ch))
3487 {
3488 pchWord += 1;
3489 cchLeft -= 1;
3490 }
3491 else if ( ch == '\\'
3492 && cchLeft > pCompiler->cchEolSeq
3493 && pchWord[1] == pCompiler->chFirstEol)
3494 {
3495 pchWord += pCompiler->cchEscEolSeq;
3496 cchLeft -= pCompiler->cchEscEolSeq;
3497 pCompiler->iEscEol++;
3498 }
3499 else
3500 break;
3501 }
3502
3503 *pcchLeft = cchLeft;
3504 return pchWord;
3505}
3506
3507
3508#if 0
3509/**
3510 * Used to shed trailing spaces in a string by decrementing @ a_cchLeft.
3511 *
3512 * @param a_pCompiler The compiler instance data.
3513 * @param a_pchWord The current input position, this will not be
3514 * changed.
3515 * @param a_cchLeft The number of chars left to parse. This will be
3516 * updated if there are trailing spaces.
3517 */
3518#define KMK_CC_EVAL_SHED_TRAILING_SPACES(a_pCompiler, a_pchWord, a_cchLeft) \
3519 do { \
3520 if ((a_cchLeft) > 0) \
3521 { \
3522 char const chShedTrailing1 = (a_pchWord)[(a_cchLeft) - 1]; \
3523 if (KMK_CC_EVAL_IS_SPACE(chShedTrailing1)) \
3524 { \
3525 /* If there are two or more, or any of these are potential EOL chars, call worker. */ \
3526 if (!KMK_CC_EVAL_IS_EOL_CANDIDATE(chShedTrailing1)) \
3527 { \
3528 (a_cchLeft) -= 1; \
3529 if ((a_cchLeft) > 0) \
3530 { \
3531 char const chShedTrailing2 = (a_pchWord)[(a_cchLeft) - 1]; \
3532 if (KMK_CC_EVAL_IS_SPACE(chShedTrailing)) \
3533 (a_cchLeft) = kmk_cc_eval_shed_trailing_spaces_slow(a_pchWord, (a_cchLeft), \
3534 chShedTrailing2, a_pCompiler); \
3535 } \
3536 } \
3537 else \
3538 (a_cchWord) = kmk_cc_eval_shed_trailing_spaces_slow(a_pchWord, (a_cchLeft), \
3539 chShedTrailing1, a_pCompiler); \
3540 } \
3541 } \
3542 } while (0)
3543
3544
3545
3546/**
3547 * The slow path of KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD.
3548 *
3549 * It's called when a space or backslash is encountered as the 2nd character.
3550 * A second space is likely to be followed by more spaces, while an escaped
3551 * newline (if it checks out) is very likely to be followed by more spaces or
3552 * tabs before we get to anything worthwhile. Also, checking for an esacped
3553 * end-of-line character is a bit tedious. (It could be worse, though, as we
3554 * know that any EOL sequence inside the text area we're currently working on
3555 * must be escaped.)
3556 *
3557 * @returns Points to the first non-space character or end of input.
3558 * @param pchWord The current position. There is some kind of char
3559 * @param cchLeft The number of chars left to parse at @a pchWord.
3560 * @param ch The current tail character.
3561 * @param pCompiler The compiler instance data.
3562 */
3563static size_t kmk_cc_eval_shed_trailing_spaces_slow(const char *pchWord, size_t cchLeft, char ch,
3564 PKMKCCEVALCOMPILER pCompiler)
3565{
3566 for (;;)
3567 {
3568 if (KMK_CC_EVAL_IS_EOL_CANDIDATE(chShedTrailing1))
3569 {
3570
3571 }
3572
3573 }
3574}
3575#endif
3576
3577
3578/**
3579 * Skips to the end of a variable name.
3580 *
3581 * This may advance pCompiler->iEscEol.
3582 *
3583 * @returns Pointer to the first char after the variable name.
3584 * @param pCompiler The compiler state.
3585 * @param pchWord The current position. Must be at the start of the
3586 * variable name.
3587 * @param cchLeft The number of chars left to parse in the current line.
3588 * @param pcchLeft The to store the updated count of characters left to
3589 * parse.
3590 * @param pfPlain Where to store the plain variable name indicator.
3591 * Returns 0 if plain, and 1 if there are variable
3592 * references in it.
3593 */
3594static const char *kmk_cc_eval_skip_var_name(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft,
3595 size_t *pcchLeft, int *pfPlain)
3596{
3597 const char * const pszContent = pCompiler->pszContent;
3598 size_t off = pchWord - pszContent;
3599 size_t const offLineEnd = off + cchLeft;
3600 int fPlain = 1;
3601 unsigned iEscEol = pCompiler->iEscEol;
3602
3603 /* Check our expectations. */
3604 KMK_CC_ASSERT(cchLeft);
3605 KMK_CC_ASSERT(!KMK_CC_EVAL_IS_SPACE(*pchWord));
3606 KMK_CC_ASSERT(iEscEol <= pCompiler->cEscEols);
3607 KMK_CC_ASSERT( iEscEol >= pCompiler->cEscEols
3608 || off < pCompiler->paEscEols[iEscEol].offEol);
3609 KMK_CC_ASSERT(off >= (iEscEol == 0 ? pCompiler->offLine : pCompiler->paEscEols[iEscEol - 1].offEol + pCompiler->cchEolSeq));
3610
3611 /*
3612 * The outer loop parses plain text. Variable expansion ($) is handled
3613 * by an inner loop.
3614 */
3615 while (off < offLineEnd)
3616 {
3617 char ch = pszContent[off];
3618 if (!KMK_CC_EVAL_IS_SPACE_OR_VAR_OR_RECIPE(ch))
3619 off++;
3620 else
3621 {
3622 if (KMK_CC_EVAL_IS_SPACE(ch))
3623 break;
3624
3625 if (ch == '$')
3626 {
3627 off++;
3628 if (off < offLineEnd)
3629 {
3630 char const chOpen = pszContent[off];
3631 if (chOpen == '(' || chOpen == '{')
3632 {
3633 /*
3634 * Got a $(VAR) or ${VAR} to deal with here. This may
3635 * include nested variable references and span multiple
3636 * lines (at least for function calls).
3637 *
3638 * We scan forward till we've found the corresponding
3639 * closing parenthesis, considering any open parentheses
3640 * of the same kind as worth counting, even if there are
3641 * no dollar preceeding them, just like GNU make does.
3642 */
3643 size_t const offStart = off - 1;
3644 char const chClose = chOpen == '(' ? ')' : '}';
3645 unsigned cOpen = 1;
3646 for (;;)
3647 {
3648 if (off < offLineEnd)
3649 {
3650 ch = pszContent[off];
3651 if (!(KMK_CC_EVAL_IS_PAREN_OR_SLASH(ch)))
3652 off++;
3653 else
3654 {
3655 off++;
3656 if (ch == chClose)
3657 {
3658 if (--cOpen == 0)
3659 break;
3660 }
3661 else if (ch == chOpen)
3662 cOpen++;
3663 else if ( ch == '\\'
3664 && iEscEol < pCompiler->cEscEols
3665 && off == pCompiler->paEscEols[iEscEol].offEsc)
3666 {
3667 off = pCompiler->paEscEols[iEscEol].offEsc + pCompiler->cchEolSeq;
3668 iEscEol++;
3669 pCompiler->iEscEol = iEscEol;
3670 }
3671 }
3672 }
3673 else if (cOpen == 1)
3674 kmk_cc_eval_fatal(pCompiler, &pszContent[offStart],
3675 "Variable reference is missing '%c'", chClose);
3676 else
3677 kmk_cc_eval_fatal(pCompiler, &pszContent[offStart],
3678 "%u variable references are missing '%c'", cOpen, chClose);
3679 }
3680 }
3681 /* Single char variable name. */
3682 else if (!KMK_CC_EVAL_IS_SPACE(chOpen))
3683 { /* likely */ }
3684 else
3685 kmk_cc_eval_fatal(pCompiler, &pszContent[off], "Expected variable name after '$', not end of line");
3686 }
3687 else
3688 kmk_cc_eval_fatal(pCompiler, &pszContent[off], "Expected variable name after '$', not end of line");
3689 fPlain = 0;
3690 }
3691 /* Deal with potential escaped EOL. */
3692 else if ( ch != '\\'
3693 || iEscEol >= pCompiler->cEscEols
3694 || off != pCompiler->paEscEols[iEscEol].offEsc )
3695 off++;
3696 else
3697 break;
3698 }
3699 }
3700
3701 *pcchLeft = offLineEnd - off;
3702 *pfPlain = fPlain;
3703 return &pszContent[off];
3704}
3705
3706
3707#if 0 /* unused atm */
3708/**
3709 * Prepares for copying a command line.
3710 *
3711 * The current version of this code will not modify any of the paEscEols
3712 * entries, unlike our kmk_cc_eval_prep_normal_line sibling function.
3713 *
3714 * @returns The number of chars that will be copied by
3715 * kmk_cc_eval_copy_prepped_command_line().
3716 * @param pCompiler The compiler instance data.
3717 * @param pchLeft Pointer to the first char to copy from the current line.
3718 * This does not have to the start of a word.
3719 * @param cchLeft The number of chars left on the current line starting at
3720 * @a pchLeft.
3721 */
3722static size_t kmk_cc_eval_prep_command_line(PKMKCCEVALCOMPILER pCompiler, const char * const pchLeft, size_t cchLeft)
3723{
3724 size_t cchRet;
3725 unsigned iEscEol = pCompiler->iEscEol;
3726 unsigned const cEscEols = pCompiler->cEscEols;
3727
3728 KMK_CC_ASSERT(cchLeft > 0);
3729 KMK_CC_ASSERT(iEscEol <= cEscEols);
3730
3731 if (iEscEol >= cEscEols)
3732 {
3733 /*
3734 * No escaped EOLs left, dead simple.
3735 */
3736 cchRet = cchLeft;
3737 }
3738 else
3739 {
3740 /*
3741 * Compared to the normal prepping of a line, this is actually
3742 * really simple. We need to account for two kind of conversions:
3743 * - One leading tab is skipped after escaped EOL.
3744 * - Convert EOL to LF.
3745 */
3746 const char * const pszContent = pCompiler->pszContent;
3747 size_t const cchEolSeq = pCompiler->cchEolSeq;
3748
3749#ifdef KMK_CC_STRICT
3750 size_t const offLeft = pchLeft - pszContent;
3751 KMK_CC_ASSERT(offLeft + cchLeft <= pCompiler->offLine + pCompiler->cchLine);
3752 KMK_CC_ASSERT(offLeft + cchLeft <= pCompiler->cchContent);
3753 KMK_CC_ASSERT(offLeft < pCompiler->paEscEols[iEscEol].offEsc);
3754 KMK_CC_ASSERT(offLeft >= (iEscEol ? pCompiler->paEscEols[cEscEols - 1].offEol + pCompiler->cchEolSeq : pCompiler->offLine));
3755#endif
3756
3757 cchRet = cchLeft;
3758 if (cchEolSeq > 1)
3759 cchRet -= (cchEolSeq - 1) * cEscEols;
3760 do
3761 {
3762 if (pszContent[pCompiler->paEscEols[cchEolSeq].offEol])
3763 cchRet--;
3764 iEscEol++;
3765 } while (iEscEol < cEscEols);
3766 }
3767 return cchRet;
3768}
3769
3770
3771/**
3772 * Copies a command line to the buffer @a pszDst points to.
3773 *
3774 * Must only be used immediately after kmk_cc_eval_prep_command_line().
3775 *
3776 * @returns
3777 * @param pCompiler The compiler instance data.
3778 * @param pchLeft Pointer to the first char to copy from the current line.
3779 * This does not have to the start of a word.
3780 * @param cchPrepped The return value of kmk_cc_eval_prep_command_line().
3781 * @param pszDst The destination buffer, must be at least @a cchPrepped
3782 * plus one (terminator) char big.
3783 */
3784static void kmk_cc_eval_copy_prepped_command_line(PKMKCCEVALCOMPILER pCompiler, const char *pchLeft,
3785 size_t cchPrepped, char *pszDst)
3786{
3787 unsigned iEscEol = pCompiler->iEscEol;
3788 unsigned const cEscEols = pCompiler->cEscEols;
3789 if (iEscEol >= cEscEols)
3790 {
3791 /* Single line. */
3792 memcpy(pszDst, pchLeft, cchPrepped);
3793 pszDst[cchPrepped] = '\0';
3794 }
3795 else
3796 {
3797 /* Multiple lines with normalized EOL and maybe one stripped leading TAB. */
3798 char * const pszDstStart = pszDst;
3799 const char * const pszContent = pCompiler->pszContent;
3800 size_t const cchEolSeq = pCompiler->cchEolSeq;
3801 size_t offLeft = pchLeft - pCompiler->pszContent;
3802 size_t cchCopy;
3803
3804 do
3805 {
3806 size_t offEol = pCompiler->paEscEols[iEscEol].offEsc;
3807 cchCopy = offEol - offLeft;
3808 KMK_CC_ASSERT(offEol >= offLeft);
3809
3810 memcpy(pszDst, &pszContent[offLeft], cchCopy);
3811 pszDst += cchCopy;
3812 *pszDst += '\n';
3813
3814 offLeft = offEol + cchEolSeq;
3815 if (pszContent[offLeft] == '\t')
3816 offLeft++;
3817 } while (iEscEol < cEscEols);
3818
3819 cchCopy = cchPrepped - (pszDst - pszDstStart);
3820 KMK_CC_ASSERT(cchCopy <= cchPrepped);
3821 memcpy(pszDst, &pszContent[offLeft], cchCopy);
3822 pszDst += cchCopy;
3823
3824 *pszDst = '\0';
3825 KMK_CC_ASSERT(pszDst == &pszDstStart[cchPrepped]);
3826 }
3827}
3828#endif /* unused atm */
3829
3830
3831/**
3832 * Gather string from segments and optional space insertion trick.
3833 *
3834 * @param pszDst The destination buffer.
3835 * @param paSegs The source segments.
3836 * @param cSegs The number of segments.
3837 * @param cchDstPrepped The size of pszDst, excluding the terminator.
3838 */
3839static void kmk_cc_eval_strcpyv(char *pszDst, PCKMKCCEVALSTRCPYSEG paSegs, unsigned cSegs, size_t cchDstPrepped)
3840{
3841 const char *pszDstStart = pszDst;
3842 unsigned iSeg = 0;
3843 while (iSeg < cSegs)
3844 {
3845 size_t cchToCopy;
3846 if (paSegs[iSeg].cchSrcAndPrependSpace >= 0)
3847 cchToCopy = paSegs[iSeg].cchSrcAndPrependSpace;
3848 else
3849 {
3850 cchToCopy = -paSegs[iSeg].cchSrcAndPrependSpace;
3851 *pszDst++ = ' ';
3852 }
3853
3854 memcpy(pszDst, paSegs[iSeg].pchSrc, cchToCopy);
3855 pszDst += cchToCopy;
3856
3857 iSeg++;
3858 }
3859 *pszDst = '\0';
3860 KMK_CC_ASSERT(pszDst == &pszDstStart[cchDstPrepped]); K_NOREF(pszDstStart); K_NOREF(cchDstPrepped);
3861}
3862
3863/**
3864 * Helper for ensuring that we've got sufficient number of string copy segments.
3865 */
3866#define KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(a_pCompiler, a_cRequiredSegs) \
3867 do { \
3868 if ((a_cRequiredSegs) < (a_pCompiler)->cStrCopySegsAllocated) \
3869 { /* likely */ } \
3870 else \
3871 { \
3872 unsigned cSegs = ((a_cRequiredSegs) + 3 /*15*/) & ~(unsigned)3/*15*/; \
3873 KMK_CC_ASSERT((a_cRequiredSegs) < 0x8000); \
3874 (a_pCompiler)->paStrCopySegs = (PKMKCCEVALSTRCPYSEG)xmalloc(cSegs * sizeof((a_pCompiler)->paStrCopySegs)[0]); \
3875 } \
3876 } while (0)
3877
3878
3879/**
3880 * Prepares for copying a normal line, extended version.
3881 *
3882 * This does not assume that we start on a word, it can handle any starting
3883 * character. It can also prepare partial copies.
3884 *
3885 * In addition to the returned information, this will store instruction in
3886 * paEscEols for the following kmk_cc_eval_strcpyv() call.
3887 *
3888 * This will advance pCompiler->iEscEol, so that it's possible to use the common
3889 * macros and helpers for parsing what comes afterwards.
3890 *
3891 * @returns The number of chars that will be copied by kmk_cc_eval_strcpyv().
3892 * @param pCompiler The compiler instance data.
3893 * @param pchWord Pointer to the first char to copy from the
3894 * current line. This must be the start of a
3895 * word.
3896 * @param cchLeft The number of chars left on the current line
3897 * starting at @a pchWord.
3898 */
3899static size_t kmk_cc_eval_prep_normal_line_ex(PKMKCCEVALCOMPILER pCompiler, const char * const pchWord, size_t cchLeft)
3900{
3901 size_t cchRet;
3902 unsigned iEscEol = pCompiler->iEscEol;
3903 unsigned const cEscEols = pCompiler->cEscEols;
3904
3905 KMK_CC_ASSERT(iEscEol <= cEscEols);
3906
3907 if (cchLeft > 0)
3908 {
3909 /*
3910 * If there are no escaped EOLs left, just copy exactly
3911 * what was passed in.
3912 */
3913 if (iEscEol >= cEscEols)
3914 {
3915 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, 1);
3916 pCompiler->cStrCopySegs = 1;
3917 pCompiler->paStrCopySegs[0].pchSrc = pchWord;
3918 pCompiler->paStrCopySegs[0].cchSrcAndPrependSpace = cchRet = cchLeft;
3919 }
3920 /*
3921 * Ok, we have to deal with escaped EOLs and do the proper
3922 * replacement of escaped newlines with space. The deal is that we
3923 * collaps all whitespace before and after one or more newlines into a
3924 * single space. (FreeBSD make does this differently, by the by.)
3925 */
3926 else
3927 {
3928 const char * const pszContent = pCompiler->pszContent;
3929 size_t offWord = pchWord - pCompiler->pszContent;
3930 size_t const offLineEnd = offWord + cchLeft; /* Note! Not necessarily end of line.*/
3931 size_t offEsc;
3932 size_t fPendingSpace = 0;
3933 unsigned cSegs = 0;
3934 size_t cchSeg;
3935
3936 /* Go nuts checking our preconditions here. */
3937 KMK_CC_ASSERT(offWord >= pCompiler->offLine);
3938 KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->offLine + pCompiler->cchLine);
3939 KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->cchContent);
3940 KMK_CC_ASSERT(offWord <= pCompiler->paEscEols[iEscEol].offEsc);
3941 KMK_CC_ASSERT(offWord >= (iEscEol ? pCompiler->paEscEols[cEscEols - 1].offEol + pCompiler->cchEolSeq
3942 : pCompiler->offLine));
3943 KMK_CC_ASSERT(offWord < offLineEnd);
3944
3945 /* Make sure we've got more than enough segments to fill in. */
3946 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, cEscEols - iEscEol + 2);
3947
3948 /*
3949 * All but the last line.
3950 */
3951 cchRet = 0;
3952 do
3953 {
3954 KMK_CC_ASSERT(offWord < offLineEnd);
3955 offEsc = pCompiler->paEscEols[iEscEol].offEsc;
3956 if (offWord < offEsc)
3957 {
3958 /* Strip trailing spaces. */
3959 while (offEsc > offWord && KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1]))
3960 offEsc--;
3961 cchSeg = offEsc - offWord;
3962 if (cchSeg)
3963 {
3964 /* Add segment. */
3965 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord];
3966 if (offEsc < offLineEnd)
3967 {
3968 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace
3969 ? -(ssize_t)cchSeg : (ssize_t)cchSeg;
3970 cchRet += cchSeg + fPendingSpace;
3971 cSegs += 1;
3972 fPendingSpace = 1;
3973 }
3974 else
3975 {
3976 cchSeg = offLineEnd - offWord;
3977 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace
3978 ? -(ssize_t)cchSeg : (ssize_t)cchSeg;
3979 pCompiler->cStrCopySegs = cSegs + 1;
3980 pCompiler->iEscEol = iEscEol;
3981 return cchRet + cchSeg + fPendingSpace;
3982 }
3983 }
3984 }
3985 else
3986 KMK_CC_ASSERT(offWord == offEsc);
3987
3988 /* Next line. */
3989 offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq;
3990 iEscEol++;
3991
3992 /* Strip leading spaces. */
3993 while (offWord < offLineEnd && KMK_CC_EVAL_IS_SPACE(pszContent[offWord]))
3994 offWord++;
3995 if (offWord >= offLineEnd)
3996 {
3997 pCompiler->cStrCopySegs = cSegs;
3998 pCompiler->iEscEol = iEscEol;
3999 return cchRet;
4000 }
4001 } while (iEscEol < cEscEols);
4002
4003 /*
4004 * The last line.
4005 */
4006 cchSeg = offLineEnd - offWord;
4007 cchRet += cchSeg;
4008 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord];
4009 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace
4010 ? -(ssize_t)cchSeg : (ssize_t)cchSeg;
4011 pCompiler->cStrCopySegs = cSegs + 1;
4012 pCompiler->iEscEol = iEscEol;
4013 }
4014 }
4015 /*
4016 * Odd case: Nothing to copy.
4017 */
4018 else
4019 {
4020 cchRet = 0;
4021 pCompiler->cStrCopySegs = 0;
4022 }
4023 return cchRet;
4024}
4025
4026
4027/**
4028 * Prepares for copying a normal line, from the given position all the way to
4029 * the end.
4030 *
4031 * In addition to the returned information, this will store instruction in
4032 * paStrCopySegs and cSTrCopySeg for the following kmk_cc_eval_strcpyv() call.
4033 *
4034 * @returns The number of chars that will be copied by kmk_cc_eval_strcpyv().
4035 * @param pCompiler The compiler instance data.
4036 * @param pchWord Pointer to the first char to copy from the
4037 * current line. This must be the start of a
4038 * word.
4039 * @param cchLeft The number of chars left on the current line
4040 * starting at @a pchWord.
4041 * @param fStripTrailingSpaces Whether to strip trailing spaces.
4042 */
4043static size_t kmk_cc_eval_prep_normal_line(PKMKCCEVALCOMPILER pCompiler, const char * const pchWord, size_t cchLeft,
4044 int fStripTrailingSpaces)
4045{
4046 size_t cchRet;
4047 unsigned iEscEol = pCompiler->iEscEol;
4048 unsigned const cEscEols = pCompiler->cEscEols;
4049
4050 KMK_CC_ASSERT(cchLeft > 0);
4051 KMK_CC_ASSERT(!KMK_CC_EVAL_IS_SPACE(*pchWord)); /* The fact that we're standing at a word, is exploited below. */
4052 KMK_CC_ASSERT(iEscEol <= cEscEols);
4053
4054 /*
4055 * If there are no escaped EOLs left, just copy what was specified,
4056 * optionally sans any trailing spaces.
4057 */
4058 if (iEscEol >= cEscEols)
4059 {
4060 cchRet = cchLeft;
4061 if (fStripTrailingSpaces)
4062 while (cchRet > 0 && KMK_CC_IS_SPACE_CH(pchWord[cchRet - 1]))
4063 cchRet--;
4064
4065 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, 1);
4066 pCompiler->cStrCopySegs = 1;
4067 pCompiler->paStrCopySegs[0].pchSrc = pchWord;
4068 pCompiler->paStrCopySegs[0].cchSrcAndPrependSpace = cchRet;
4069 }
4070 /*
4071 * Ok, we have to deal with escaped EOLs and do the proper
4072 * replacement of escaped newlines with space. The deal is that we
4073 * collaps all whitespace before and after one or more newlines into a
4074 * single space. (FreeBSD make does this differently, by the by.)
4075 */
4076 else
4077 {
4078 const char *pszContent = pCompiler->pszContent;
4079 size_t offWord = pchWord - pCompiler->pszContent;
4080 size_t offEsc;
4081 size_t fPendingSpace;
4082 size_t cchSeg;
4083 unsigned cSegs = 0;
4084
4085 /* Go nuts checking our preconditions here. */
4086 KMK_CC_ASSERT(offWord >= pCompiler->offLine);
4087 KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->offLine + pCompiler->cchLine);
4088 KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->cchContent);
4089 KMK_CC_ASSERT(offWord < pCompiler->paEscEols[iEscEol].offEsc);
4090 KMK_CC_ASSERT(offWord >= (iEscEol ? pCompiler->paEscEols[cEscEols - 1].offEol + pCompiler->cchEolSeq : pCompiler->offLine));
4091
4092 /* Make sure we've got more than enough segments to fill in. */
4093 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, cEscEols - iEscEol + 2);
4094
4095 /*
4096 * First line - We're at the start of a word, so no left stripping needed.
4097 */
4098 offEsc = pCompiler->paEscEols[iEscEol].offEsc;
4099 KMK_CC_ASSERT(offEsc > offWord);
4100 while (KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1]))
4101 offEsc--;
4102 KMK_CC_ASSERT(offEsc > offWord);
4103
4104 fPendingSpace = 1;
4105 cchRet = offEsc - offWord;
4106 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = cchRet;
4107 pCompiler->paStrCopySegs[cSegs].pchSrc = pchWord;
4108
4109 offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq;
4110 iEscEol++;
4111
4112 /*
4113 * All but the last line.
4114 */
4115 while (iEscEol < cEscEols)
4116 {
4117 offEsc = pCompiler->paEscEols[iEscEol].offEsc;
4118
4119 /* Strip leading spaces. */
4120 while (offWord < offEsc && KMK_CC_EVAL_IS_SPACE(pszContent[offWord]))
4121 offWord++;
4122
4123 if (offWord < offEsc)
4124 {
4125 /* Strip trailing spaces. */
4126 while (KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1]))
4127 offEsc--;
4128 cchSeg = offEsc - offWord;
4129 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace ? -(ssize_t)cchSeg : (ssize_t)cchSeg;
4130 cchRet += cchSeg + fPendingSpace;
4131 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord];
4132 cSegs += 1;
4133 fPendingSpace = 1;
4134 }
4135
4136 /* Next. */
4137 offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq;
4138 iEscEol++;
4139 }
4140
4141 /*
4142 * Final line. We must calculate the end of line offset our selves here.
4143 */
4144 offEsc = &pchWord[cchLeft] - pszContent;
4145 while (offWord < offEsc && KMK_CC_EVAL_IS_SPACE(pszContent[offWord]))
4146 offWord++;
4147
4148 if (offWord < offEsc)
4149 {
4150 if (fStripTrailingSpaces)
4151 while (KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1]))
4152 offEsc--;
4153 cchSeg = offEsc - offWord;
4154 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace ? -(ssize_t)cchSeg : (ssize_t)cchSeg;
4155 cchRet += cchSeg + fPendingSpace;
4156 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord];
4157 cSegs += 1;
4158 }
4159
4160 pCompiler->cStrCopySegs = cSegs;
4161 }
4162 return cchRet;
4163}
4164
4165
4166/**
4167 * Common worker for all kmk_cc_eval_do_if*() functions.
4168 *
4169 * @param pCompiler The compiler state.
4170 * @param pIfCore The new IF statement.
4171 * @param fInElse Set if this is an 'else if' (rather than just 'if').
4172 */
4173static void kmk_cc_eval_do_if_core(PKMKCCEVALCOMPILER pCompiler, PKMKCCEVALIFCORE pIfCore, int fInElse)
4174{
4175 unsigned iIf = pCompiler->cIfs;
4176 if (!fInElse)
4177 {
4178 /* Push an IF statement. */
4179 if (iIf < KMK_CC_EVAL_MAX_IF_DEPTH)
4180 {
4181 pCompiler->cIfs = iIf + 1;
4182 pCompiler->apIfs[iIf] = pIfCore;
4183 pIfCore->pPrevCond = NULL;
4184 }
4185 else
4186 kmk_cc_eval_fatal(pCompiler, NULL, "Too deep IF nesting");
4187 }
4188 else if (iIf > 0)
4189 {
4190 /* Link an IF statement. */
4191 iIf--;
4192 pIfCore->pPrevCond = pCompiler->apIfs[iIf];
4193 pCompiler->apIfs[iIf] = pIfCore;
4194 }
4195 else
4196 kmk_cc_eval_fatal(pCompiler, NULL, "'else if' without 'if'");
4197 pIfCore->pNextTrue = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail);
4198 pIfCore->pNextFalse = NULL; /* This is set by else or endif. */
4199 pIfCore->pTrueEndJump = NULL; /* This is set by else or endif. */
4200}
4201
4202
4203/**
4204 * Deals with 'if expr' and 'else if expr' statements.
4205 *
4206 * @returns 1 to indicate we've handled a keyword (see
4207 * kmk_cc_eval_try_handle_keyword).
4208 * @param pCompiler The compiler state.
4209 * @param pchWord First char after 'define'.
4210 * @param cchLeft The number of chars left to parse on this line.
4211 * @param fInElse Set if this is an 'else if' (rather than just 'if').
4212 */
4213static int kmk_cc_eval_do_if(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse)
4214{
4215 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4216 if (cchLeft)
4217 {
4218 size_t cchExpr = kmk_cc_eval_prep_normal_line(pCompiler, pchWord, cchLeft, 1 /*fStripTrailingSpaces*/);
4219 PKMKCCEVALIFEXPR pInstr = (PKMKCCEVALIFEXPR)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail,
4220 KMKCCEVALIFEXPR_SIZE(cchExpr));
4221 kmk_cc_eval_strcpyv(pInstr->szExpr, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, cchExpr);
4222 pInstr->cchExpr = cchExpr;
4223 pInstr->IfCore.Core.enmOpCode = kKmkCcEvalInstr_if;
4224 pInstr->IfCore.Core.iLine = pCompiler->iLine;
4225 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse);
4226 }
4227 else
4228 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive");
4229 return 1;
4230}
4231
4232
4233/**
4234 * Deals with 'ifdef var', 'ifndef var', 'else ifdef var' and 'else ifndef var'
4235 * statements.
4236 *
4237 * @returns 1 to indicate we've handled a keyword (see
4238 * kmk_cc_eval_try_handle_keyword).
4239 * @param pCompiler The compiler state.
4240 * @param pchWord First char after 'define'.
4241 * @param cchLeft The number of chars left to parse on this line.
4242 * @param fInElse Set if this is an 'else if' (rather than just 'if').
4243 * @param fPositiveStmt Set if 'ifdef', clear if 'ifndef'.
4244 */
4245static int kmk_cc_eval_do_ifdef(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt)
4246{
4247 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4248 if (cchLeft)
4249 {
4250 /*
4251 * Skip to the end of the variable name.
4252 */
4253 unsigned const iSavedEscEol = pCompiler->iEscEol;
4254 const char * const pchVarNm = pchWord;
4255 int fPlain;
4256 pchWord = kmk_cc_eval_skip_var_name(pCompiler, pchWord, cchLeft, &cchLeft, &fPlain);
4257 KMK_CC_ASSERT(pCompiler->iEscEol == iSavedEscEol || !fPlain);
4258 if (fPlain)
4259 {
4260 size_t const cchVarNm = pchWord - pchVarNm;
4261 PKMKCCEVALIFDEFPLAIN pInstr;
4262 pInstr = (PKMKCCEVALIFDEFPLAIN)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
4263 pInstr->IfCore.Core.enmOpCode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_plain : kKmkCcEvalInstr_ifndef_plain;
4264 pInstr->IfCore.Core.iLine = pCompiler->iLine;
4265 pInstr->pszName = strcache2_add(&variable_strcache, pchVarNm, cchVarNm);
4266 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse);
4267 }
4268 else
4269 {
4270 PKMKCCEVALIFDEFDYNAMIC pInstr;
4271 size_t const cchVarNm = pchWord - pchVarNm;
4272 size_t cchCopy;
4273 char *pszCopy;
4274 pCompiler->iEscEol = iSavedEscEol;
4275 cchCopy = kmk_cc_eval_prep_normal_line(pCompiler, pchVarNm, cchVarNm, 0 /*fStripTrailingSpaces*/);
4276
4277 pInstr = (PKMKCCEVALIFDEFDYNAMIC)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
4278
4279 /** @todo Make the subprogram embed necessary strings. */
4280 pszCopy = kmk_cc_block_alloc_eval_string(pCompiler->ppBlockTail, cchCopy + 1);
4281 kmk_cc_eval_strcpyv(pszCopy, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, cchCopy);
4282
4283 pInstr->IfCore.Core.enmOpCode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_dynamic : kKmkCcEvalInstr_ifndef_dynamic;
4284 pInstr->IfCore.Core.iLine = pCompiler->iLine;
4285 kmk_cc_eval_compile_string_exp_subprog(pCompiler, pszCopy, cchCopy, &pInstr->NameSubprog);
4286
4287 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse);
4288 }
4289
4290 /*
4291 * Make sure there is nothing following the variable name.
4292 */
4293 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4294 if (cchLeft)
4295 kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'if%sdef' variable name", fPositiveStmt ? "" : "n");
4296 }
4297 else
4298 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive");
4299 return 1;
4300}
4301
4302
4303static int kmk_cc_eval_do_ifeq(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt)
4304{
4305 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4306 if (cchLeft)
4307 {
4308 /*
4309 * There are two forms:
4310 *
4311 * ifeq (string1, string2)
4312 * ifeq "string1" 'string2'
4313 *
4314 */
4315 const char * const pchEnd = &pchWord[cchLeft];
4316 PKMKCCEVALIFEQ pInstr;
4317
4318 struct
4319 {
4320 char *pszCopy;
4321 size_t cchCopy;
4322 int fPlain;
4323 } Left, Right;
4324
4325 char ch = *pchWord;
4326 if (ch == '(')
4327 {
4328// unsigned cCounts;
4329
4330
4331
4332 /* Skip the parenthesis. */
4333 pchWord++;
4334 cchLeft--;
4335
4336/** @todo continue here. */
4337 }
4338 else if (ch == '"' || ch == '\'')
4339 {
4340 const char *pchTmp;
4341
4342 /*
4343 * Quoted left side.
4344 */
4345 /* Skip leading quote. */
4346 pchWord++;
4347 cchLeft--;
4348
4349 /* Locate the end quote. */
4350 pchTmp = (const char *)memchr(pchWord, ch, cchLeft);
4351 if (pchTmp) { /* likely */ }
4352 else kmk_cc_eval_fatal(pCompiler, pchWord - 1, "Unbalanced quote in first if%seq string", fPositiveStmt ? "" : "n");
4353
4354 Left.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, pchTmp - pchWord);
4355 Left.pszCopy = kmk_cc_block_alloc_eval_string(pCompiler->ppBlockTail, Left.cchCopy + 1);
4356 kmk_cc_eval_strcpyv(Left.pszCopy, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, Left.cchCopy);
4357 Left.fPlain = memchr(Left.pszCopy, '$', Left.cchCopy) == NULL;
4358
4359 /* skip end quote */
4360 pchWord = pchTmp + 1;
4361 cchLeft = pchEnd - pchWord;
4362
4363 /* Skip anything inbetween the left and right hand side (not mandatory). */
4364 if ( cchLeft /** @todo replace with straight 'isspace' that takes escaped EOLs into account. */
4365 && KMK_CC_EVAL_IS_SPACE_AFTER_WORD(pCompiler, pchWord[0], pchWord[1], cchLeft))
4366 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4367
4368 /*
4369 * Quoted right side.
4370 */
4371 if ( cchLeft > 0
4372 && ( (ch = *pchWord) != '"' || ch == '\'') )
4373 {
4374 /* Skip leading quote. */
4375 pchWord++;
4376 cchLeft--;
4377
4378 /* Locate the end quote. */
4379 pchTmp = (const char *)memchr(pchWord, ch, cchLeft);
4380 if (pchTmp) { /* likely */ }
4381 else kmk_cc_eval_fatal(pCompiler, pchWord - 1, "Unbalanced quote in second if%seq string", fPositiveStmt ? "" : "n");
4382
4383 Right.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, pchTmp - pchWord);
4384 Right.pszCopy = kmk_cc_block_alloc_eval_string(pCompiler->ppBlockTail, Right.cchCopy + 1);
4385 kmk_cc_eval_strcpyv(Left.pszCopy, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, Right.cchCopy);
4386 Right.fPlain = memchr(Right.pszCopy, '$', Right.cchCopy) == NULL;
4387
4388 /* skip end quote */
4389 pchWord = pchTmp + 1;
4390 cchLeft = pchEnd - pchWord;
4391 }
4392 else
4393 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected a second quoted string for 'if%seq'",
4394 fPositiveStmt ? "" : "n");
4395 }
4396 else
4397 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected parentheses or quoted string after 'if%seq'",
4398 fPositiveStmt ? "" : "n");
4399
4400 /*
4401 *
4402 */
4403 pInstr = (PKMKCCEVALIFEQ)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
4404
4405
4406 /*
4407 * Make sure there is nothing following the variable name.
4408 */
4409 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4410 if (cchLeft)
4411 kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'if%sdef' variable name", fPositiveStmt ? "" : "n");
4412 }
4413 else
4414 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive");
4415 return 1;
4416}
4417
4418
4419static int kmk_cc_eval_do_if1of(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt)
4420{
4421 return 1;
4422}
4423
4424
4425/**
4426 * Deals with 'else' and 'else ifxxx' statements.
4427 *
4428 * @returns 1 to indicate we've handled a keyword (see
4429 * kmk_cc_eval_try_handle_keyword).
4430 * @param pCompiler The compiler state.
4431 * @param pchWord First char after 'define'.
4432 * @param cchLeft The number of chars left to parse on this line.
4433 */
4434static int kmk_cc_eval_do_else(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
4435{
4436 /*
4437 * There must be an 'if' on the stack.
4438 */
4439 unsigned iIf = pCompiler->cIfs;
4440 if (iIf > 0)
4441 {
4442 PKMKCCEVALIFCORE pIfCore = pCompiler->apIfs[--iIf];
4443 if (!pIfCore->pTrueEndJump)
4444 {
4445 /* Emit a jump instruction that will take us from the 'True' block to the 'endif'. */
4446 PKMKCCEVALJUMP pInstr = (PKMKCCEVALJUMP)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
4447 pInstr->Core.enmOpCode = kKmkCcEvalInstr_jump;
4448 pInstr->Core.iLine = pCompiler->iLine;
4449 pInstr->pNext = NULL;
4450 pIfCore->pTrueEndJump = pInstr;
4451
4452 /* The next instruction is the first in the 'False' block of the current 'if'.
4453 Should this be an 'else if', this will be the 'if' instruction emitted below. */
4454 pIfCore->pNextFalse = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail);
4455 }
4456 else if (iIf == 0)
4457 kmk_cc_eval_fatal(pCompiler, pchWord, "2nd 'else' for 'if' at line %u", pIfCore->Core.iLine);
4458 else
4459 kmk_cc_eval_fatal(pCompiler, pchWord, "2nd 'else' in a row - missing 'endif' for 'if' at line %u?",
4460 pIfCore->Core.iLine);
4461 }
4462 else
4463 kmk_cc_eval_fatal(pCompiler, pchWord, "'else' without 'if'");
4464
4465 /*
4466 * Check for 'else ifxxx'. There can be nothing else following an else.
4467 */
4468 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4469 if (cchLeft)
4470 {
4471 if ( cchLeft > 2
4472 && KMK_CC_WORD_COMP_CONST_2(pchWord, "if"))
4473 {
4474 pchWord += 2;
4475 cchLeft -= 2;
4476
4477 if (KMK_CC_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
4478 return kmk_cc_eval_do_if(pCompiler, pchWord, cchLeft, 1 /* in else */);
4479
4480 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "eq", 2))
4481 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 2, cchLeft - 2, 1 /* in else */, 1 /* positive */);
4482
4483 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "def", 3))
4484 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 1 /* positive */);
4485
4486 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "neq", 3))
4487 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 0 /* positive */);
4488
4489 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "1of", 3))
4490 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 1 /* positive */);
4491
4492 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "ndef", 4))
4493 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 4, cchLeft - 4, 1 /* in else */, 0 /* positive */);
4494
4495 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "n1of", 4))
4496 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 4, cchLeft - 4, 1 /* in else */, 0 /* positive */);
4497
4498 pchWord -= 2;
4499 cchLeft += 2;
4500 }
4501 kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'else'");
4502 }
4503
4504 return 1;
4505}
4506
4507
4508/**
4509 * Deals with the 'endif' statement.
4510 *
4511 * @returns 1 to indicate we've handled a keyword (see
4512 * kmk_cc_eval_try_handle_keyword).
4513 * @param pCompiler The compiler state.
4514 * @param pchWord First char after 'define'.
4515 * @param cchLeft The number of chars left to parse on this line.
4516 */
4517static int kmk_cc_eval_do_endif(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
4518{
4519 /*
4520 * There must be an 'if' on the stack. We'll POP it.
4521 */
4522 unsigned iIf = pCompiler->cIfs;
4523 if (iIf > 0)
4524 {
4525 PKMKCCEVALCORE pNextInstr;
4526 PKMKCCEVALIFCORE pIfCore = pCompiler->apIfs[--iIf];
4527 pCompiler->cIfs = iIf; /* POP! */
4528
4529 /* Update the jump targets for all IFs at this level. */
4530 pNextInstr = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail);
4531 do
4532 {
4533 if (pIfCore->pTrueEndJump)
4534 {
4535 /* Make the true block jump here, to the 'endif'. The false block is already here. */
4536 pIfCore->pTrueEndJump->pNext = pNextInstr;
4537 KMK_CC_ASSERT(pIfCore->pNextFalse);
4538 }
4539 else
4540 {
4541 /* No 'else'. The false-case jump here, to the 'endif'. */
4542 KMK_CC_ASSERT(!pIfCore->pNextFalse);
4543 pIfCore->pNextFalse = pNextInstr;
4544 }
4545
4546 pIfCore = pIfCore->pPrevCond;
4547 } while (pIfCore);
4548 }
4549 else
4550 kmk_cc_eval_fatal(pCompiler, pchWord, "'endif' without 'if'");
4551
4552 /*
4553 * There shouldn't be anything trailing an 'endif'.
4554 */
4555 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4556 if (!cchLeft) { /* likely */ }
4557 else kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'else'");
4558
4559 return 1;
4560}
4561
4562
4563static int kmk_cc_eval_do_include(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, KMKCCEVALINSTR enmInst)
4564{
4565 return 1;
4566}
4567
4568
4569static int kmk_cc_eval_do_vpath(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
4570{
4571 return 1;
4572}
4573
4574
4575static void kmk_cc_eval_handle_command(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
4576{
4577
4578}
4579
4580
4581static void kmk_cc_eval_handle_recipe(PKMKCCEVALCOMPILER pCompiler, const char *pszEqual, const char *pchWord, size_t cchLeft)
4582{
4583
4584}
4585
4586
4587/**
4588 * Parses a 'undefine variable [..]' expression.
4589 *
4590 * A 'undefine' directive is final, any qualifiers must preceed it. So, we just
4591 * have to extract the variable names now.
4592 *
4593 * @returns 1 to indicate we've handled a keyword (see
4594 * kmk_cc_eval_try_handle_keyword).
4595 * @param pCompiler The compiler state.
4596 * @param pchWord First char after 'define'.
4597 * @param cchLeft The number of chars left to parse on this line.
4598 * @param fQualifiers The qualifiers.
4599 */
4600static int kmk_cc_eval_do_var_undefine(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft,
4601 unsigned fQualifiers)
4602{
4603
4604 return 1;
4605}
4606
4607
4608/**
4609 * Parses a 'define variable' expression.
4610 *
4611 * A 'define' directive is final, any qualifiers must preceed it. So, we just
4612 * have to extract the variable name now, well and find the corresponding
4613 * 'endef'.
4614 *
4615 * @returns 1 to indicate we've handled a keyword (see
4616 * kmk_cc_eval_try_handle_keyword).
4617 * @param pCompiler The compiler state.
4618 * @param pchWord First char after 'define'.
4619 * @param cchLeft The number of chars left to parse on this line.
4620 * @param fQualifiers The qualifiers.
4621 */
4622static int kmk_cc_eval_do_var_define(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft,
4623 unsigned fQualifiers)
4624{
4625
4626 return 1;
4627}
4628
4629
4630static int kmk_cc_eval_try_handle_assignment(PKMKCCEVALCOMPILER pCompiler, const char *pchTmp,
4631 const char *pchWord, size_t cchLeft, unsigned fQualifiers)
4632{
4633 return 0;
4634}
4635
4636
4637/**
4638 * Parses a 'local [override] variable = value' expression.
4639 *
4640 * The 'local' directive must be first and it does not permit any qualifiers at
4641 * the moment. Should any be added later, they will have to come after 'local'.
4642 *
4643 * @returns 1 to indicate we've handled a keyword (see
4644 * kmk_cc_eval_try_handle_keyword).
4645 * @param pCompiler The compiler state.
4646 * @param pchWord First char after 'define'.
4647 * @param cchLeft The number of chars left to parse on this line.
4648 * @param fQualifiers The qualifiers.
4649 */
4650static int kmk_cc_eval_do_var_local(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
4651{
4652
4653 return 1;
4654}
4655
4656
4657/**
4658 * Parses 'export [variable]' and 'export [qualifiers] variable = value'
4659 * expressions.
4660 *
4661 * When we find the 'export' directive at the start of a line, we need to
4662 * continue parsing with till we can tell the difference between the two forms.
4663 *
4664 * @returns 1 to indicate we've handled a keyword (see
4665 * kmk_cc_eval_try_handle_keyword).
4666 * @param pCompiler The compiler state.
4667 * @param pchWord First char after 'define'.
4668 * @param cchLeft The number of chars left to parse on this line.
4669 * @param fQualifiers The qualifiers.
4670 */
4671static int kmk_cc_eval_handle_var_export(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers)
4672{
4673
4674 return 1;
4675}
4676
4677
4678/**
4679 * We've found one variable qualification keyword, now continue parsing and see
4680 * if this is some kind of variable assignment expression or not.
4681 *
4682 * @returns 1 if variable assignment, 0 if not.
4683 * @param pCompiler The compiler state.
4684 * @param pchWord First char after the first qualifier.
4685 * @param cchLeft The number of chars left to parse on this line.
4686 * @param fQualifiers The qualifier.
4687 */
4688static int kmk_cc_eval_try_handle_var_with_keywords(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft,
4689 unsigned fQualifiers)
4690{
4691 for (;;)
4692 {
4693 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4694 if (cchLeft)
4695 {
4696 char ch = *pchWord;
4697 if (KMK_CC_EVAL_IS_1ST_IN_VARIABLE_KEYWORD(ch))
4698 {
4699 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6)) /* final */
4700 return kmk_cc_eval_do_var_define(pCompiler, pchWord + 6, cchLeft - 6, fQualifiers);
4701
4702 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6)) /* special */
4703 return kmk_cc_eval_handle_var_export(pCompiler, pchWord + 6, cchLeft - 6, fQualifiers);
4704
4705 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8)) /* final */
4706 return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 6, cchLeft - 6, fQualifiers);
4707
4708 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8))
4709 {
4710 /** @todo warn if repeated. */
4711 fQualifiers |= KMK_CC_EVAL_QUALIFIER_OVERRIDE;
4712 pchWord += 8;
4713 cchLeft -= 8;
4714 continue;
4715 }
4716
4717 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7))
4718 {
4719 /** @todo warn if repeated. */
4720 fQualifiers |= KMK_CC_EVAL_QUALIFIER_PRIVATE;
4721 pchWord += 7;
4722 cchLeft -= 7;
4723 continue;
4724 }
4725 }
4726
4727 /*
4728 * Not a keyword, likely variable name followed by an assignment
4729 * operator and a value. Do a rough check for the assignment operator
4730 * and join paths with the unqualified assignment handling code.
4731 */
4732 {
4733 const char *pchEqual = (const char *)memchr(pchWord, '=', cchLeft);
4734 if (pchEqual)
4735 return kmk_cc_eval_try_handle_assignment(pCompiler, pchEqual, pchWord, cchLeft, fQualifiers);
4736 }
4737 return 0;
4738 }
4739 else
4740 kmk_cc_eval_fatal(pCompiler, NULL,
4741 "Expected assignment operator or variable directive after variable qualifier(s)\n");
4742 }
4743}
4744
4745
4746/**
4747 * When entering this function we know that the first two character in the first
4748 * word both independently occurs in keywords.
4749 *
4750 * @returns 1 if make directive or qualified variable assignment, 0 if neither.
4751 * @param pCompiler The compiler state.
4752 * @param ch The first char.
4753 * @param pchWord Pointer to the first word.
4754 * @param cchLeft Number of characters left to parse starting at
4755 * @a cchLeft.
4756 */
4757int kmk_cc_eval_try_handle_keyword(PKMKCCEVALCOMPILER pCompiler, char ch, const char *pchWord, size_t cchLeft)
4758{
4759 unsigned iSavedEscEol = pCompiler->iEscEol;
4760
4761 KMK_CC_ASSERT(cchLeft >= 2);
4762 KMK_CC_ASSERT(ch == pchWord[0]);
4763 KMK_CC_ASSERT(KMK_CC_EVAL_IS_1ST_IN_KEYWORD(pchWord[0]));
4764 KMK_CC_ASSERT(KMK_CC_EVAL_IS_2ND_IN_KEYWORD(pchWord[1]));
4765
4766 /*
4767 * If it's potentially a variable related keyword, check that out first.
4768 */
4769 if (KMK_CC_EVAL_IS_1ST_IN_VARIABLE_KEYWORD(ch))
4770 {
4771 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "local", 5))
4772 return kmk_cc_eval_do_var_local(pCompiler, pchWord + 5, cchLeft - 5);
4773 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6))
4774 return kmk_cc_eval_do_var_define(pCompiler, pchWord + 6, cchLeft - 6, 0);
4775 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6))
4776 return kmk_cc_eval_handle_var_export(pCompiler, pchWord + 6, cchLeft - 6, 0);
4777 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8))
4778 return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 8, cchLeft - 8, 0);
4779 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8))
4780 {
4781 if (kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord + 8, cchLeft - 8, KMK_CC_EVAL_QUALIFIER_OVERRIDE))
4782 return 1;
4783 pCompiler->iEscEol = iSavedEscEol;
4784 }
4785 else if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7))
4786 {
4787 if (kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord + 7, cchLeft - 7, KMK_CC_EVAL_QUALIFIER_PRIVATE))
4788 return 1;
4789 pCompiler->iEscEol = iSavedEscEol;
4790 }
4791 }
4792
4793 /*
4794 * Check out the other keywords.
4795 */
4796 if (ch == 'i') /* Lots of directives starting with 'i'. */
4797 {
4798 char ch2 = pchWord[1];
4799 pchWord += 2;
4800 cchLeft -= 2;
4801
4802 /* 'if...' */
4803 if (ch2 == 'f')
4804 {
4805 if (KMK_CC_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
4806 return kmk_cc_eval_do_if(pCompiler, pchWord, cchLeft, 0 /* in else */);
4807
4808 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "eq", 2))
4809 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 2, cchLeft - 2, 0 /* in else */, 1 /* positive */);
4810
4811 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "def", 3))
4812 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 1 /* positive */);
4813
4814 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "neq", 3))
4815 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 0 /* positive */);
4816
4817 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "1of", 3))
4818 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 1 /* positive */);
4819
4820 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "ndef", 4))
4821 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 4, cchLeft - 4, 0 /* in else */, 0 /* positive */);
4822
4823 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "n1of", 4))
4824 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 4, cchLeft - 4, 0 /* in else */, 0 /* positive */);
4825 }
4826 /* include... */
4827 else if (ch2 == 'n' && cchLeft >= 5 && KMK_CC_WORD_COMP_CONST_5(pchWord, "clude") ) /* 'in...' */
4828 {
4829 pchWord += 5;
4830 cchLeft -= 5;
4831 if (KMK_CC_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
4832 return kmk_cc_eval_do_include(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_include);
4833 if (cchLeft >= 3 && KMK_CC_WORD_COMP_CONST_3(pchWord, "dep"))
4834 {
4835 pchWord += 3;
4836 cchLeft -= 3;
4837 if (KMK_CC_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
4838 return kmk_cc_eval_do_include(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_includedep);
4839 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-queue", 6))
4840 return kmk_cc_eval_do_include(pCompiler, pchWord + 6, cchLeft - 6, kKmkCcEvalInstr_includedep_queue);
4841 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-flush", 6))
4842 return kmk_cc_eval_do_include(pCompiler, pchWord + 6, cchLeft - 6, kKmkCcEvalInstr_includedep_flush);
4843 }
4844 }
4845 }
4846 else if (ch == 'e') /* A few directives starts with 'e'. */
4847 {
4848 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "else", 4))
4849 return kmk_cc_eval_do_else(pCompiler, pchWord + 4, cchLeft - 4);
4850 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "endif", 5))
4851 return kmk_cc_eval_do_endif(pCompiler, pchWord + 5, cchLeft - 5);
4852 /* export and endef are handled elsewhere, though stray endef's may end up here... */
4853 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6));
4854
4855 }
4856 else /* the rest. */
4857 {
4858 if ( KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "sinclude", 8)
4859 || KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-include", 8))
4860 return kmk_cc_eval_do_include(pCompiler, pchWord + 8, cchLeft - 8, kKmkCcEvalInstr_include_silent);
4861 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "vpath", 5))
4862 return kmk_cc_eval_do_vpath(pCompiler, pchWord + 5, cchLeft - 5);
4863
4864 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "local", 5));
4865 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6));
4866 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7));
4867 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8));
4868 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "unexport", 8));
4869 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8));
4870 }
4871
4872 pCompiler->iEscEol = iSavedEscEol;
4873 return 0;
4874}
4875
4876
4877
4878
4879static int kmk_cc_eval_compile_worker(PKMKCCEVALPROG pEvalProg, const char *pszContent, size_t cchContent, unsigned iLine)
4880{
4881 const char *pchTmp;
4882
4883 /*
4884 * Compiler state.
4885 */
4886 KMKCCEVALCOMPILER Compiler;
4887 kmk_cc_eval_init_compiler(&Compiler, pEvalProg, iLine, pszContent, cchContent);
4888
4889 {
4890 /*
4891 * Line state.
4892 */
4893 size_t cchLine; /* The length of the current line (w/o comments). */
4894 size_t offNext = 0; /* The offset of the next line. */
4895 size_t off = 0; /* The offset into pszContent of the current line. */
4896
4897 /* Try for some register/whatever optimzations. */
4898 int const chFirstEol = Compiler.chFirstEol;
4899 size_t const cchEolSeq = Compiler.cchEolSeq;
4900
4901 /*
4902 * Process input lines.
4903 *
4904 * The code here concerns itself with getting the next line in an efficient
4905 * manner, very basic classification and trying out corresponding handlers.
4906 * The real work is done in the handlers.
4907 */
4908 while (offNext < cchContent)
4909 {
4910 size_t offFirstWord;
4911
4912 /*
4913 * Find the end of the next line.
4914 */
4915 KMK_CC_ASSERT(off == offNext);
4916
4917 /* Simple case: No escaped EOL, nor the end of the input. */
4918 pchTmp = (const char *)memchr(&pszContent[offNext], chFirstEol, cchContent - offNext);
4919 if ( pchTmp
4920 && ( &pszContent[offNext] == pchTmp
4921 || pchTmp[-1] != '\\') )
4922 {
4923 if ( cchEolSeq == 1
4924 || pchTmp[1] == Compiler.chSecondEol)
4925 {
4926 /* Frequent: Blank line. */
4927 if (&pszContent[offNext] == pchTmp)
4928 {
4929fprintf(stderr, "#%03u: <empty>\n", Compiler.iLine);
4930 Compiler.iLine++;
4931 off = offNext += cchEolSeq;
4932 continue;
4933 }
4934 if (pszContent[offNext] == '#')
4935 {
4936fprintf(stderr, "#%03u: <comment>\n", Compiler.iLine);
4937 Compiler.iLine++;
4938 offNext = pchTmp - pszContent;
4939 off = offNext += cchEolSeq;
4940 continue;
4941 }
4942
4943 offNext = pchTmp - pszContent;
4944 cchLine = offNext - off;
4945
4946 offFirstWord = off;
4947 while (offFirstWord < offNext && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord]))
4948 offFirstWord++;
4949
4950 offNext += cchEolSeq;
4951 Compiler.cEscEols = 0;
4952 Compiler.iEscEol = 0;
4953 }
4954 else
4955 kmk_cc_eval_fatal_eol(&Compiler, pchTmp, Compiler.iLine, off);
4956 }
4957 /* The complicated, less common cases. */
4958 else
4959 {
4960 Compiler.cEscEols = 0;
4961 Compiler.iEscEol = 0;
4962 offFirstWord = offNext;
4963 for (;;)
4964 {
4965 if (offFirstWord == offNext)
4966 {
4967 size_t offEol = off + cchLine;
4968 while (offFirstWord < offEol && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord]))
4969 offFirstWord++;
4970 }
4971
4972 if (pchTmp)
4973 {
4974 if ( cchEolSeq == 1
4975 || pchTmp[1] == Compiler.chSecondEol)
4976 {
4977 size_t offEsc;
4978 if (offFirstWord != offNext)
4979 offNext = pchTmp - pszContent;
4980 else
4981 {
4982 offNext = pchTmp - pszContent;
4983 while (offFirstWord < offNext && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord]))
4984 offFirstWord++;
4985 }
4986
4987
4988 /* Is it an escape sequence? */
4989 if ( !offNext
4990 || pchTmp[-1] != '\\')
4991 {
4992 cchLine = offNext - off;
4993 offNext += cchEolSeq;
4994 break;
4995 }
4996 if (offNext < 2 || pchTmp[-2] != '\\')
4997 offEsc = offNext - 1;
4998 else
4999 {
5000 /* Count how many backslashes there are. Must be odd number to be an escape
5001 sequence. Normally we keep half of them, except for command lines. */
5002 size_t cSlashes = 2;
5003 while (offNext >= cSlashes && pchTmp[0 - cSlashes] == '\\')
5004 cSlashes--;
5005 if (!(cSlashes & 1))
5006 {
5007 cchLine = offNext - off;
5008 offNext += cchEolSeq;
5009 break;
5010 }
5011 offEsc = offNext - (cSlashes >> 1);
5012 }
5013
5014 /* Record it. */
5015 if (Compiler.cEscEols < Compiler.cEscEolsAllocated) { /* likely */ }
5016 else
5017 {
5018 KMK_CC_ASSERT(Compiler.cEscEols == Compiler.cEscEolsAllocated);
5019 Compiler.cEscEolsAllocated = Compiler.cEscEolsAllocated
5020 ? Compiler.cEscEolsAllocated * 2 : 2;
5021 Compiler.paEscEols = (PKMKCCEVALESCEOL)xrealloc(Compiler.paEscEols,
5022 Compiler.cEscEolsAllocated
5023 * sizeof(Compiler.paEscEols[0]));
5024 }
5025 Compiler.paEscEols[Compiler.cEscEols].offEsc = offEsc;
5026 Compiler.paEscEols[Compiler.cEscEols].offEol = offNext;
5027 Compiler.cEscEols++;
5028
5029 /* Advance. */
5030 offNext += cchEolSeq;
5031 if (offFirstWord == offEsc)
5032 {
5033 offFirstWord = offNext;
5034 Compiler.iEscEol++;
5035 }
5036 }
5037 else
5038 kmk_cc_eval_fatal_eol(&Compiler, pchTmp, Compiler.iLine, off);
5039 }
5040 else
5041 {
5042 /* End of input. Happens only once per compilation, nothing to optimize for. */
5043 if (offFirstWord == offNext)
5044 while (offFirstWord < cchContent && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord]))
5045 offFirstWord++;
5046 offNext = cchContent;
5047 cchLine = cchContent - off;
5048 break;
5049 }
5050 pchTmp = (const char *)memchr(&pszContent[offNext], chFirstEol, cchContent - offNext);
5051 }
5052 }
5053 KMK_CC_ASSERT(offNext <= cchContent);
5054 KMK_CC_ASSERT(offNext >= off + cchLine);
5055 KMK_CC_ASSERT(off + cchLine <= cchContent && cchLine <= cchContent);
5056 KMK_CC_ASSERT(offFirstWord <= off + cchLine);
5057 KMK_CC_ASSERT(offFirstWord >= off);
5058 KMK_CC_ASSERT(pszContent[offFirstWord] != ' ' && pszContent[offFirstWord] != '\t');
5059{
5060char chSaved = ((char *)pszContent)[off+cchLine] = '\0';
5061fprintf(stderr, "#%03u: %s\n", Compiler.iLine, &pszContent[off]);
5062((char *)pszContent)[off+cchLine] = chSaved;
5063}
5064
5065 /*
5066 * Skip blank lines.
5067 */
5068 if (offFirstWord < off + cchLine)
5069 {
5070 /*
5071 * Command? Ignore command prefix if no open recipe (SunOS 4 behavior).
5072 */
5073 if ( pszContent[off] == Compiler.chCmdPrefix
5074 && (Compiler.pRecipe || Compiler.fNoTargetRecipe))
5075 {
5076 if (!Compiler.fNoTargetRecipe)
5077 kmk_cc_eval_handle_command(&Compiler, &pszContent[off], cchLine);
5078 }
5079 /*
5080 * Since it's not a command line, we can now skip comment lines
5081 * even with a tab indentation. If it's not a comment line, we
5082 * tentatively strip any trailing comment.
5083 */
5084 else if (pszContent[offFirstWord] != '#')
5085 {
5086 const char *pchWord = &pszContent[offFirstWord];
5087 size_t cchLeft = off + cchLine - offFirstWord;
5088 char ch;
5089
5090 Compiler.cchLineWithComments = cchLine;
5091 pchTmp = (const char *)memchr(pchWord, '#', cchLeft);
5092 if (pchTmp)
5093 {
5094 cchLeft = pchTmp - pchWord;
5095 cchLine = pchTmp - &pszContent[off];
5096 }
5097 Compiler.cchLine = cchLine;
5098 Compiler.offLine = off;
5099
5100 /*
5101 * If not a directive or variable qualifier, it's either a variable
5102 * assignment or a recipe.
5103 */
5104 ch = *pchWord;
5105 if ( !KMK_CC_EVAL_IS_1ST_IN_KEYWORD(ch)
5106 || !KMK_CC_EVAL_IS_2ND_IN_KEYWORD(pchWord[1])
5107 || !kmk_cc_eval_try_handle_keyword(&Compiler, ch, pchWord, cchLeft) )
5108 {
5109 pchTmp = (const char *)memchr(pchWord, '=', cchLeft);
5110 if ( !pchTmp
5111 || !kmk_cc_eval_try_handle_assignment(&Compiler, pchTmp, pchWord, cchLeft, 0) )
5112 kmk_cc_eval_handle_recipe(&Compiler, pchTmp, pchWord, cchLeft);
5113 }
5114 /* else: handled a keyword expression */
5115 }
5116 }
5117
5118 /*
5119 * Advance to the next line.
5120 */
5121 off = offNext;
5122 Compiler.iLine += Compiler.cEscEols + 1;
5123 }
5124 }
5125
5126 /*
5127 * Check whether
5128 */
5129
5130 kmk_cc_eval_delete_compiler(&Compiler);
5131 return 0;
5132}
5133
5134
5135/*#define KMK_CC_EVAL_ENABLE*/
5136
5137static PKMKCCEVALPROG kmk_cc_eval_compile(const char *pszContent, size_t cchContent,
5138 const char *pszFilename, unsigned iLine, const char *pszVarName)
5139{
5140 /*
5141 * Estimate block size, allocate one and initialize it.
5142 */
5143 PKMKCCEVALPROG pEvalProg;
5144 PKMKCCBLOCK pBlock;
5145 pEvalProg = kmk_cc_block_alloc_first(&pBlock, sizeof(*pEvalProg), cchContent / 32); /** @todo adjust */
5146 if (pEvalProg)
5147 {
5148 pEvalProg->pBlockTail = pBlock;
5149 pEvalProg->pFirstInstr = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(pBlock);
5150 pEvalProg->pszFilename = pszFilename ? pszFilename : "<unknown>";
5151 pEvalProg->pszVarName = pszVarName;
5152 pEvalProg->cRefs = 1;
5153#ifdef KMK_CC_STRICT
5154 pEvalProg->uInputHash = kmk_cc_debug_string_hash_n(0, pszContent, cchContent);
5155#endif
5156
5157 /*
5158 * Do the actual compiling.
5159 */
5160#ifdef KMK_CC_EVAL_ENABLE
5161 if (kmk_cc_eval_compile_worker(pEvalProg, pszContent, cchContent, iLine) == 0)
5162#else
5163 if (0)
5164#endif
5165 {
5166#ifdef KMK_CC_WITH_STATS
5167 pBlock = pEvalProg->pBlockTail;
5168 if (!pBlock->pNext)
5169 g_cSingleBlockEvalProgs++;
5170 else if (!pBlock->pNext->pNext)
5171 g_cTwoBlockEvalProgs++;
5172 else
5173 g_cMultiBlockEvalProgs++;
5174 for (; pBlock; pBlock = pBlock->pNext)
5175 {
5176 g_cBlocksAllocatedEvalProgs++;
5177 g_cbAllocatedEvalProgs += pBlock->cbBlock;
5178 g_cbUnusedMemEvalProgs += pBlock->cbBlock - pBlock->offNext;
5179 }
5180#endif
5181 return pEvalProg;
5182 }
5183 kmk_cc_block_free_list(pEvalProg->pBlockTail);
5184 }
5185 return NULL;
5186}
5187
5188
5189/**
5190 * Compiles a variable direct evaluation as is, setting v->evalprog on success.
5191 *
5192 * @returns Pointer to the program on success, NULL if no program was created.
5193 * @param pVar Pointer to the variable.
5194 */
5195struct kmk_cc_evalprog *kmk_cc_compile_variable_for_eval(struct variable *pVar)
5196{
5197 PKMKCCEVALPROG pEvalProg = pVar->evalprog;
5198 if (!pEvalProg)
5199 {
5200#ifdef KMK_CC_EVAL_ENABLE
5201 pEvalProg = kmk_cc_eval_compile(pVar->value, pVar->value_length,
5202 pVar->fileinfo.filenm, pVar->fileinfo.lineno, pVar->name);
5203 pVar->evalprog = pEvalProg;
5204#endif
5205 g_cVarForEvalCompilations++;
5206 }
5207 return pEvalProg;
5208}
5209
5210
5211/**
5212 * Compiles a makefile for
5213 *
5214 * @returns Pointer to the program on success, NULL if no program was created.
5215 * @param pVar Pointer to the variable.
5216 */
5217struct kmk_cc_evalprog *kmk_cc_compile_file_for_eval(FILE *pFile, const char *pszFilename)
5218{
5219 PKMKCCEVALPROG pEvalProg;
5220
5221 /*
5222 * Read the entire file into a zero terminate memory buffer.
5223 */
5224 size_t cchContent = 0;
5225 char *pszContent = NULL;
5226 struct stat st;
5227 if (!fstat(fileno(pFile), &st))
5228 {
5229 if ( st.st_size > (off_t)16*1024*1024
5230 && st.st_size < 0)
5231 fatal(NULL, _("Makefile too large to compile: %ld bytes (%#lx) - max 16MB"), (long)st.st_size, (long)st.st_size);
5232 cchContent = (size_t)st.st_size;
5233 pszContent = (char *)xmalloc(cchContent + 1);
5234
5235 cchContent = fread(pszContent, 1, cchContent, pFile);
5236 if (ferror(pFile))
5237 fatal(NULL, _("Read error: %s"), strerror(errno));
5238 }
5239 else
5240 {
5241 size_t cbAllocated = 2048;
5242 do
5243 {
5244 cbAllocated *= 2;
5245 if (cbAllocated > 16*1024*1024)
5246 fatal(NULL, _("Makefile too large to compile: max 16MB"));
5247 pszContent = (char *)xrealloc(pszContent, cbAllocated);
5248 cchContent += fread(&pszContent[cchContent], 1, cbAllocated - 1 - cchContent, pFile);
5249 if (ferror(pFile))
5250 fatal(NULL, _("Read error: %s"), strerror(errno));
5251 } while (!feof(pFile));
5252 }
5253 pszContent[cchContent] = '\0';
5254
5255 /*
5256 * Call common function to do the compilation.
5257 */
5258 pEvalProg = kmk_cc_eval_compile(pszContent, cchContent, pszFilename, 1, NULL /*pszVarName*/);
5259 g_cFileForEvalCompilations++;
5260
5261 free(pszContent);
5262 if (!pEvalProg)
5263 fseek(pFile, 0, SEEK_SET);
5264 return pEvalProg;
5265}
5266
5267
5268/**
5269 * Equivalent of eval_buffer, only it's using the evalprog of the variable.
5270 *
5271 * @param pVar Pointer to the variable. Must have a program.
5272 */
5273void kmk_exec_eval_variable(struct variable *pVar)
5274{
5275 KMK_CC_ASSERT(pVar->evalprog);
5276 assert(0);
5277}
5278
5279
5280/**
5281 * Worker for eval_makefile.
5282 *
5283 * @param pEvalProg The program pointer.
5284 */
5285void kmk_exec_eval_file(struct kmk_cc_evalprog *pEvalProg)
5286{
5287 KMK_CC_ASSERT(pEvalProg);
5288 assert(0);
5289}
5290
5291
5292
5293/*
5294 *
5295 * Program destruction hooks.
5296 * Program destruction hooks.
5297 * Program destruction hooks.
5298 *
5299 */
5300
5301
5302/**
5303 * Called when a variable with expandprog or/and evalprog changes.
5304 *
5305 * @param pVar Pointer to the variable.
5306 */
5307void kmk_cc_variable_changed(struct variable *pVar)
5308{
5309 PKMKCCEXPPROG pProg = pVar->expandprog;
5310
5311 KMK_CC_ASSERT(pVar->evalprog || pProg);
5312
5313 if (pVar->evalprog)
5314 {
5315 kmk_cc_block_free_list(pVar->evalprog->pBlockTail);
5316 pVar->evalprog = NULL;
5317 }
5318
5319 if (pProg)
5320 {
5321 if (pProg->cRefs == 1)
5322 kmk_cc_block_free_list(pProg->pBlockTail);
5323 else
5324 fatal(NULL, _("Modifying a variable (%s) while its expansion program is running is not supported"), pVar->name);
5325 pVar->expandprog = NULL;
5326 }
5327}
5328
5329
5330/**
5331 * Called when a variable with expandprog or/and evalprog is deleted.
5332 *
5333 * @param pVar Pointer to the variable.
5334 */
5335void kmk_cc_variable_deleted(struct variable *pVar)
5336{
5337 PKMKCCEXPPROG pProg = pVar->expandprog;
5338
5339 KMK_CC_ASSERT(pVar->evalprog || pProg);
5340
5341 if (pVar->evalprog)
5342 {
5343 kmk_cc_block_free_list(pVar->evalprog->pBlockTail);
5344 pVar->evalprog = NULL;
5345 }
5346
5347 if (pProg)
5348 {
5349 if (pProg->cRefs == 1)
5350 kmk_cc_block_free_list(pProg->pBlockTail);
5351 else
5352 fatal(NULL, _("Deleting a variable (%s) while its expansion program is running is not supported"), pVar->name);
5353 pVar->expandprog = NULL;
5354 }
5355}
5356
5357
5358
5359
5360
5361
5362
5363#endif /* CONFIG_WITH_COMPILER */
5364
Note: See TracBrowser for help on using the repository browser.

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