Changes in / [af746cc:dc58e5d]


Ignore:
Files:
1 deleted
18 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/mike_brooks_MMath/background.tex

    raf746cc rdc58e5d  
    11\chapter{Background}
    22
    3 Since this work builds on C, it is necessary to explain the C mechanisms and their shortcomings for array, linked list, and string,
     3Since this work builds on C, it is necessary to explain the C mechanisms and their shortcomings for array, linked list, and string.
    44
    55
     
    4545Hence, in all cases, @sizeof@ is informing about type information.
    4646
    47 So, thinking of an array as a pointer to its first element is too simplistic an analogue and it is not backed up the type system.
    48 This misguided analogue can be forced onto single-dimension arrays but there is no advantage other than possibly teaching beginning programmers about basic runtime array-access.
    49 
    50 Continuing, a shortened form for declaring local variables exists, provided that length information is given in the initializer:
     47So, thinking of an array as a pointer to its first element is too simplistic an analogue and it is not backed up by the type system.
     48This misguided analogue works for a single-dimension array but there is no advantage other than possibly teaching beginning programmers about basic runtime array-access.
     49
     50Continuing, a short form for declaring array variables exists using length information provided implicitly by an initializer.
    5151\lstinput{59-62}{bkgd-carray-arrty.c}
    52 In these declarations, the resulting types are both arrays, but their lengths are inferred.
    53 
    54 My contribution is enabled by recognizing
     52The compiler counts the number of initializer elements and uses this value as the first dimension.
     53Unfortunately, the implicit element counting does not extend to dimensions beyond the first.
     54\lstinput{64-67}{bkgd-carray-arrty.c}
     55
     56My contribution is recognizing:
    5557\begin{itemize}
    56         \item There is value in using a type that knows how big the whole thing is.
     58        \item There is value in using a type that knows its size.
    5759        \item The type pointer to (first) element does not.
    5860        \item C \emph{has} a type that knows the whole picture: array, e.g. @T[10]@.
    59         \item This type has all the usual derived forms, which also know the whole picture.  A usefully noteworthy example is pointer to array, e.g. @T(*)[10]@.
     61        \item This type has all the usual derived forms, which also know the whole picture.
     62        A usefully noteworthy example is pointer to array, e.g. @T (*)[10]@.\footnote{
     63        The parenthesis are necessary because subscript has higher priority than pointer in C declarations.
     64        (Subscript also has higher priority than dereference in C expressions.)}
    6065\end{itemize}
    6166
    62 Each of these sections, which introduces another layer of of the C arrays' story,
    63 concludes with an \emph{Unfortunate Syntactic Reference}.
    64 It shows how to spell the types under discussion,
    65 along with interactions with orthogonal (but easily confused) language features.
    66 Alternate spellings are listed within a row.
     67
     68\section{Reading Declarations}
     69
     70A significant area of confusion for reading C declarations results from embedding a declared variable in a declaration, mimicking the way the variable is used in executable statements.
     71\begin{cquote}
     72\begin{tabular}{@{}ll@{}}
     73\multicolumn{1}{@{}c}{\textbf{Array}} & \multicolumn{1}{c@{}}{\textbf{Function Pointer}} \\
     74\begin{cfa}
     75int @(*@ar@)[@5@]@; // definition
     76  ... @(*@ar@)[@3@]@ += 1; // usage
     77\end{cfa}
     78&
     79\begin{cfa}
     80int @(*@f@())[@5@]@ { ... }; // definition
     81  ... @(*@f@())[@3@]@ += 1; // usage
     82\end{cfa}
     83\end{tabular}
     84\end{cquote}
     85Essentially, the type is wrapped around the name in successive layers (like an \Index{onion}).
     86While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice, even though Dennis Richie believed otherwise:
     87\begin{quote}
     88In spite of its difficulties, I believe that the C's approach to declarations remains plausible, and am comfortable with it; it is a useful unifying principle.~\cite[p.~12]{Ritchie93}
     89\end{quote}
     90After all, reading a C array type is easy: just read it from the inside out, and know when to look left and when to look right!
     91
     92\CFA provides its own type, variable and routine declarations, using a simpler syntax.
     93The new declarations place qualifiers to the left of the base type, while C declarations place qualifiers to the right of the base type.
     94The qualifiers have the same meaning in \CFA as in C.
     95Then, a \CFA declaration is read left to right, where a function return type is enclosed in brackets @[@\,@]@.
     96\begin{cquote}
     97\begin{tabular}{@{}l@{\hspace{3em}}ll@{}}
     98\multicolumn{1}{c@{\hspace{3em}}}{\textbf{C}}   & \multicolumn{1}{c}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{read left to right}}   \\
     99\begin{cfa}
     100int @*@ x1 @[5]@;
     101int @(*@x2@)[5]@;
     102int @(*@f( int p )@)[5]@;
     103\end{cfa}
     104&
     105\begin{cfa}
     106@[5] *@ int x1;
     107@* [5]@ int x2;
     108@[ * [5] int ]@ f( int p );
     109\end{cfa}
     110&
     111\begin{cfa}
     112// array of 5 pointers to int
     113// pointer to array of 5 int
     114// function returning pointer to array of 5 ints
     115\end{cfa}
     116\\
     117& &
     118\LstCommentStyle{//\ \ \ and taking an int argument}
     119\end{tabular}
     120\end{cquote}
     121As declaration complexity increases, it becomes corresponding difficult to read and understand the C declaration form.
     122Note, writing declarations left to right is common in other programming languages, where the function return-type is often placed after the parameter declarations.
     123
     124\VRef[Table]{bkgd:ar:usr:avp} introduces the many layers of the C and \CFA array story, where the \CFA story is discussion in \VRef{XXX}.
     125The \CFA-thesis column shows the new array declaration form, which is my contributed improvements for safety and ergonomics.
     126The table shows there are multiple yet equivalent forms for the array types under discussion, and subsequent discussion shows interactions with orthogonal (but easily confused) language features.
     127Each row of the table shows alternate syntactic forms.
    67128The simplest occurrences of types distinguished in the preceding discussion are marked with $\triangleright$.
    68 The Type column gives the spelling used in a cast or error message (though note Section TODO points out that some types cannot be casted to).
    69 The Declaration column gives the spelling used in an object declaration, such as variable or aggregate member; parameter declarations (section TODO) follow entirely different rules.
    70 
    71 After all, reading a C array type is easy: just read it from the inside out, and know when to look left and when to look right!
    72 
    73 
    74 \CFA-specific spellings (not yet introduced) are also included here for referenceability; these can be skipped on linear reading.
    75 The \CFA-C column gives the, more fortunate, ``new'' syntax of section TODO, for spelling \emph{exactly the same type}.
    76 This fortunate syntax does not have different spellings for types vs declarations;
    77 a declaration is always the type followed by the declared identifier name;
    78 for the example of letting @x@ be a \emph{pointer to array}, the declaration is spelled:
    79 \begin{cfa}
    80 [ * [10] T ] x;
    81 \end{cfa}
    82 The \CFA-Full column gives the spelling of a different type, introduced in TODO, which has all of my contributed improvements for safety and ergonomics.
    83 
    84 \VRef[Figure]{bkgd:ar:usr:avp} gives this reference for the discussion so far.
    85 
    86 \begin{figure}
     129Removing the declared variable @x@, gives the type used for variable, structure field, cast or error messages \PAB{(though note Section TODO points out that some types cannot be casted to)}.
     130Unfortunately, parameter declarations \PAB{(section TODO)} have more syntactic forms and rules.
     131
     132\begin{table}
    87133\centering
    88 \setlength{\tabcolsep}{3pt}
    89 \begin{tabular}{llllll}
    90         & Description & Type & Declaration & \CFA-C  & \CFA-Full \\ \hline
    91         $\triangleright$ & val.
    92             & @T@
    93             & @T x;@
    94             & @[ T ]@
    95             &
    96             \\ \hline
    97         & \pbox{20cm}{ \vspace{2pt} val.\\ \footnotesize{no writing the val.\ in \lstinline{x}}   }\vspace{2pt}
    98             & \pbox{20cm}{ \vspace{2pt} \lstinline{const T} \\ \lstinline{T const}   }
    99             & \pbox{20cm}{ \vspace{2pt} \lstinline{const T x;} \\ \lstinline{T const x;}   }
    100             & @[ const T ]@
    101             &
    102             \\ \hline \hline
    103         $\triangleright$ & ptr.\ to val.
    104             & @T *@
    105             & @T * x;@
    106             & @[ * T ]@
    107             &
    108             \\ \hline
    109         & \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x}}   }\vspace{2pt}
    110             & @T * const@
    111             & @T * const x;@
    112             & @[ const * T ]@
    113             &
    114             \\ \hline
    115         & \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{*x}}   }\vspace{2pt}
    116             & \pbox{20cm}{ \vspace{2pt} \lstinline{const T *} \\ \lstinline{T const *}   }
    117             & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * x;} \\ \lstinline{T const * x;}   }
    118             & @[ * const T ]@
    119             &
    120             \\ \hline \hline
    121         $\triangleright$ & ar.\ of val.
    122             & @T[10]@
    123             & @T x[10];@
    124             & @[ [10] T ]@
    125             & @[ array(T, 10) ]@
    126             \\ \hline
    127         & \pbox{20cm}{ \vspace{2pt} ar.\ of val.\\ \footnotesize{no writing the val.\ in \lstinline{x[5]}}   }\vspace{2pt}
    128             & \pbox{20cm}{ \vspace{2pt} \lstinline{const T[10]} \\ \lstinline{T const[10]}   }
    129             & \pbox{20cm}{ \vspace{2pt} \lstinline{const T x[10];} \\ \lstinline{T const x[10];}   }
    130             & @[ [10] const T ]@
    131             & @[ const array(T, 10) ]@
    132             \\ \hline
    133         & ar.\ of ptr.\ to val.
    134             & @T*[10]@
    135             & @T *x[10];@
    136             & @[ [10] * T ]@
    137             & @[ array(* T, 10) ]@
    138             \\ \hline
    139         & \pbox{20cm}{ \vspace{2pt} ar.\ of ptr.\ to val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x[5]}}   }\vspace{2pt}
    140             & @T * const [10]@
    141             & @T * const x[10];@
    142             & @[ [10] const * T ]@
    143             & @[ array(const * T, 10) ]@
    144             \\ \hline
    145         & \pbox{20cm}{ \vspace{2pt} ar.\ of ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{*(x[5])}}   }\vspace{2pt}
    146             & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * [10]} \\ \lstinline{T const * [10]}   }
    147             & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * x[10];} \\ \lstinline{T const * x[10];}   }
    148             & @[ [10] * const T ]@
    149             & @[ array(* const T, 10) ]@
    150             \\ \hline \hline
    151         $\triangleright$ & ptr.\ to ar.\ of val.
    152             & @T(*)[10]@
    153             & @T (*x)[10];@
    154             & @[ * [10] T ]@
    155             & @[ * array(T, 10) ]@
    156             \\ \hline
    157         & \pbox{20cm}{ \vspace{2pt} ptr.\ to ar.\ of val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x}}   }\vspace{2pt}
    158             & @T(* const)[10]@
    159             & @T (* const x)[10];@
    160             & @[ const * [10] T ]@
    161             & @[ const * array(T, 10) ]@
    162             \\ \hline
    163         & \pbox{20cm}{ \vspace{2pt} ptr.\ to ar.\ of val.\\ \footnotesize{no writing the val.\ in \lstinline{(*x)[5]}}   }\vspace{2pt}
    164             & \pbox{20cm}{ \vspace{2pt} \lstinline{const T(*)[10]} \\ \lstinline{T const (*) [10]}   }
    165             & \pbox{20cm}{ \vspace{2pt} \lstinline{const T (*x)[10];} \\ \lstinline{T const (*x)[10];}   }
    166             & @[ * [10] const T ]@
    167             & @[ * const array(T, 10) ]@
    168             \\ \hline
    169         & ptr.\ to ar.\ of ptr.\ to val.
    170             & @T*(*)[10]@
    171             & @T *(*x)[10];@
    172             & @[ * [10] * T ]@
    173             & @[ * array(* T, 10) ]@
    174             \\ \hline
     134\caption{Syntactic Reference for Array vs Pointer. Includes interaction with \lstinline{const}ness.}
     135\label{bkgd:ar:usr:avp}
     136\begin{tabular}{ll|l|l|l}
     137        & Description & \multicolumn{1}{c|}{C} & \multicolumn{1}{c|}{\CFA}  & \multicolumn{1}{c}{\CFA-thesis} \\
     138        \hline
     139$\triangleright$ & value & @T x;@ & @T x;@ & \\
     140        \hline
     141        & immutable value & @const T x;@ & @const T x;@ & \\
     142        & & @T const x;@ & @T const x;@ & \\
     143        \hline \hline
     144$\triangleright$ & pointer to value & @T * x;@ & @* T x;@ & \\
     145        \hline
     146        & immutable ptr. to val. & @T * const x;@ & @const * T x;@ & \\
     147        \hline
     148        & ptr. to immutable val. & @const T * x;@ & @* const T x;@ & \\
     149        & & @T const * x;@ & @* T const x;@ & \\
     150        \hline \hline
     151$\triangleright$ & array of value & @T x[10];@ & @[10] T x@ & @array(T, 10) x@ \\
     152        \hline
     153        & ar.\ of immutable val. & @const T x[10];@ & @[10] const T x@ & @const array(T, 10) x@ \\
     154    & & @T const x[10];@ & @[10] T const x@ & @array(T, 10) const x@ \\
     155        \hline
     156        & ar.\ of ptr.\ to value & @T * x[10];@ & @[10] * T x@ & @array(T *, 10) x@ \\
     157        & & & & @array(* T, 10) x@ \\
     158        \hline
     159        & ar.\ of imm. ptr.\ to val. & @T * const x[10];@ & @[10] const * T x@ & @array(* const T, 10) x@ \\
     160        & & & & @array(const * T, 10) x@ \\
     161        \hline
     162        & ar.\ of ptr.\ to imm. val. & @const T * x[10];@ & @[10] * const T x@ & @array(const T *, 10) x@ \\
     163        & & @T const * x[10];@ & @[10] * T const x@ & @array(* const T, 10) x@ \\
     164        \hline \hline
     165$\triangleright$ & ptr.\ to ar.\ of value & @T (*x)[10];@ & @* [10] T x@ & @* array(T, 10) x@ \\
     166        \hline
     167        & imm. ptr.\ to ar.\ of val. & @T (* const x)[10];@ & @const * [10] T x@ & @const * array(T, 10) x@ \\
     168        \hline
     169        & ptr.\ to ar.\ of imm. val. & @const T (*x)[10];@ & @* [10] const T x@ & @* const array(T, 10) x@ \\
     170        & & @T const (*x)[10];@ & @* [10] T const x@ & @* array(T, 10) const x@ \\
     171        \hline
     172        & ptr.\ to ar.\ of ptr.\ to val. & @T *(*x)[10];@ & @* [10] * T x@ & @* array(T *, 10) x@ \\
     173        & & & & @* array(* T, 10) x@ \\
     174        \hline
    175175\end{tabular}
    176 \caption{Unfortunate Syntactic Reference for Array vs Pointer.  Includes interaction with constness.}
    177 \label{bkgd:ar:usr:avp}
    178 \end{figure}
    179 
    180 
    181 
    182 
     176\end{table}
    183177
    184178TODO: Address these parked unfortunate syntaxes
     
    186180        \item static
    187181        \item star as dimension
    188         \item under pointer decay:                              int p1[const 3]  being  int const *p1
     182        \item under pointer decay: @int p1[const 3]@ being @int const *p1@
    189183\end{itemize}
    190184
     
    203197\lstinput{10-10}{bkgd-carray-decay.c}
    204198
    205 So, C provides an implicit conversion from @float[10]@ to @float*@, as described in ARM-6.3.2.1.3:
     199So, C provides an implicit conversion from @float[10]@ to @float *@.
    206200\begin{quote}
    207 Except when it is the operand of the @sizeof@ operator, or the unary @&@ operator, or is a
    208 string literal used to initialize an array
    209 an expression that has type ``array of type'' is
    210 converted to an expression with type ``pointer to type'' that points to the initial element of
    211 the array object
     201Except when it is the operand of the @sizeof@ operator, or the unary @&@ operator, or is a string literal used to
     202initialize an array an expression that has type ``array of \emph{type}'' is converted to an expression with type
     203``pointer to \emph{type}'' that points to the initial element of the array object~\cite[\S~6.3.2.1.3]{C11}
    212204\end{quote}
    213 
    214205This phenomenon is the famous ``pointer decay,'' which is a decay of an array-typed expression into a pointer-typed one.
    215 
    216206It is worthy to note that the list of exception cases does not feature the occurrence of @ar@ in @ar[i]@.
    217 Thus, subscripting happens on pointers, not arrays.
    218 
    219 Subscripting proceeds first with pointer decay, if needed.  Next, ARM-6.5.2.1.2 explains that @ar[i]@ is treated as if it were @(*((a)+(i)))@.
    220 ARM-6.5.6.8 explains that the addition, of a pointer with an integer type,  is defined only when the pointer refers to an element that is in an array, with a meaning of ``@i@ elements away from,'' which is valid if @ar@ is big enough and @i@ is small enough.
    221 Finally, ARM-6.5.3.2.4 explains that the @*@ operator's result is the referenced element.
    222 
    223 Taken together, these rules also happen to illustrate that @ar[i]@ and @i[a]@ mean the same thing.
     207Thus, subscripting happens on pointers not arrays.
     208
     209Subscripting proceeds first with pointer decay, if needed.  Next, \cite[\S~6.5.2.1.2]{C11} explains that @ar[i]@ is treated as if it were @(*((a)+(i)))@.
     210\cite[\S~6.5.6.8]{C11} explains that the addition, of a pointer with an integer type,  is defined only when the pointer refers to an element that is in an array, with a meaning of ``@i@ elements away from,'' which is valid if @ar@ is big enough and @i@ is small enough.
     211Finally, \cite[\S~6.5.3.2.4]{C11} explains that the @*@ operator's result is the referenced element.
     212Taken together, these rules illustrate that @ar[i]@ and @i[a]@ mean the same thing!
    224213
    225214Subscripting a pointer when the target is standard-inappropriate is still practically well-defined.
     
    233222fs[5] = 3.14;
    234223\end{cfa}
    235 The @malloc@ behaviour is specified as returning a pointer to ``space for an object whose size is'' as requested (ARM-7.22.3.4.2).
    236 But program says \emph{nothing} more about this pointer value, that might cause its referent to \emph{be} an array, before doing the subscript.
    237 
    238 Under this assumption, a pointer being subscripted (or added to, then dereferenced)
    239 by any value (positive, zero, or negative), gives a view of the program's entire address space,
    240 centred around the @p@ address, divided into adjacent @sizeof(*p)@ chunks,
    241 each potentially (re)interpreted as @typeof(*p)@.
    242 
    243 I call this phenomenon ``array diffraction,''  which is a diffraction of a single-element pointer
    244 into the assumption that its target is in the middle of an array whose size is unlimited in both directions.
    245 
     224The @malloc@ behaviour is specified as returning a pointer to ``space for an object whose size is'' as requested (\cite[\S~7.22.3.4.2]{C11}).
     225But \emph{nothing} more is said about this pointer value, specifically that its referent might \emph{be} an array allowing subscripting.
     226
     227Under this assumption, a pointer being subscripted (or added to, then dereferenced) by any value (positive, zero, or negative), gives a view of the program's entire address space, centred around the @p@ address, divided into adjacent @sizeof(*p)@ chunks, each potentially (re)interpreted as @typeof(*p)@.
     228I call this phenomenon ``array diffraction,''  which is a diffraction of a single-element pointer into the assumption that its target is in the middle of an array whose size is unlimited in both directions.
    246229No pointer is exempt from array diffraction.
    247 
    248230No array shows its elements without pointer decay.
    249231
    250232A further pointer--array confusion, closely related to decay, occurs in parameter declarations.
    251 ARM-6.7.6.3.7 explains that when an array type is written for a parameter,
    252 the parameter's type becomes a type that I summarize as being the array-decayed type.
    253 The respective handlings of the following two parameter spellings shows that the array-spelled one is really, like the other, a pointer.
     233\cite[\S~6.7.6.3.7]{C11} explains that when an array type is written for a parameter,
     234the parameter's type becomes a type that can be summarized as the array-decayed type.
     235The respective handling of the following two parameter spellings shows that the array-spelled one is really, like the other, a pointer.
    254236\lstinput{12-16}{bkgd-carray-decay.c}
    255237As the @sizeof(x)@ meaning changed, compared with when run on a similarly-spelled local variable declaration,
    256 GCC also gives this code the warning: ```sizeof' on array function parameter `x' will return size of `float *'.''
    257 
    258 The caller of such a function is left with the reality that a pointer parameter is a pointer, no matter how it's spelled:
     238@gcc@ also gives this code the warning for the first assertion:
     239\begin{cfa}
     240warning: 'sizeof' on array function parameter 'x' will return size of 'float *'
     241\end{cfa}
     242The caller of such a function is left with the reality that a pointer parameter is a pointer, no matter how it is spelled:
    259243\lstinput{18-21}{bkgd-carray-decay.c}
    260244This fragment gives no warnings.
     
    272256depending on whether the object is a local variable or a parameter.
    273257
    274 
    275258In summary, when a function is written with an array-typed parameter,
    276259\begin{itemize}
     
    283266As a result, a function with a pointer-to-array parameter sees the parameter exactly as the caller does:
    284267\lstinput{32-42}{bkgd-carray-decay.c}
    285 
    286 \VRef[Figure]{bkgd:ar:usr:decay-parm} gives the reference for the decay phenomenon seen in parameter decalarations.
    287 
    288 \begin{figure}
     268\VRef[Table]{bkgd:ar:usr:decay-parm} gives the reference for the decay phenomenon seen in parameter declarations.
     269
     270\begin{table}
     271\caption{Syntactic Reference for Decay during Parameter-Passing.
     272Includes interaction with \lstinline{const}ness, where ``immutable'' refers to a restriction on the callee's ability.}
     273\label{bkgd:ar:usr:decay-parm}
    289274\centering
    290275\begin{tabular}{llllll}
    291         & Description & Type & Param. Decl & \CFA-C  \\ \hline
    292         $\triangleright$ & ptr.\ to val.
    293             & @T *@
    294             & \pbox{20cm}{ \vspace{2pt} \lstinline{T * x,} \\ \lstinline{T x[10],} \\ \lstinline{T x[],}   }\vspace{2pt}
    295             & \pbox{20cm}{ \vspace{2pt} \lstinline{[ * T ]} \\ \lstinline{[ [10] T ]} \\ \lstinline{[ [] T  ]}   }
    296             \\ \hline
    297         & \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x}}   }\vspace{2pt}
    298             & @T * const@
    299             & \pbox{20cm}{ \vspace{2pt} \lstinline{T * const x,} \\ \lstinline{T x[const 10],} \\ \lstinline{T x[const],}   }\vspace{2pt}
    300             & \pbox{20cm}{ \vspace{2pt} \lstinline{[ const * T ]} \\ \lstinline{[ [const 10] T ]} \\ \lstinline{[ [const] T  ]}   }
    301             \\ \hline
    302         & \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{*x}}   }\vspace{2pt}
    303             & \pbox{20cm}{ \vspace{2pt} \lstinline{const T *} \\ \lstinline{T const *}   }
    304             & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * x,} \\ \lstinline{T const * x,} \\ \lstinline{const T x[10],} \\ \lstinline{T const x[10],} \\ \lstinline{const T x[],} \\ \lstinline{T const x[],}   }\vspace{2pt}
    305             & \pbox{20cm}{ \vspace{2pt} \lstinline{[* const T]} \\ \lstinline{[ [10] const T ]} \\ \lstinline{[ [] const T  ]}   }
    306             \\ \hline \hline
    307         $\triangleright$ & ptr.\ to ar.\ of val.
    308             & @T(*)[10]@
    309             & \pbox{20cm}{ \vspace{2pt} \lstinline{T (*x)[10],} \\ \lstinline{T x[3][10],} \\ \lstinline{T x[][10],}   }\vspace{2pt}
    310             & \pbox{20cm}{ \vspace{2pt} \lstinline{[* [10] T]} \\ \lstinline{[ [3] [10] T ]} \\ \lstinline{[ [] [10] T  ]}   }
    311             \\ \hline
    312         & ptr.\ to ptr.\ to val.
    313             & @T **@
    314             & \pbox{20cm}{ \vspace{2pt} \lstinline{T ** x,} \\ \lstinline{T *x[10],} \\ \lstinline{T *x[],}   }\vspace{2pt}
    315             & \pbox{20cm}{ \vspace{2pt} \lstinline{[ * * T ]} \\ \lstinline{[ [10] * T ]} \\ \lstinline{[ [] * T  ]}   }
    316             \\ \hline
    317         & \pbox{20cm}{ \vspace{2pt} ptr.\ to ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{**argv}}   }\vspace{2pt}
    318             & @const char **@
    319             & \pbox{20cm}{ \vspace{2pt} \lstinline{const char *argv[],} \\ \footnotesize{(others elided)}   }\vspace{2pt}
    320             & \pbox{20cm}{ \vspace{2pt} \lstinline{[ [] * const char ]} \\ \footnotesize{(others elided)}   }
    321             \\ \hline
     276        & Description & Type & Parameter Declaration & \CFA  \\
     277        \hline
     278        & & & @T * x,@ & @* T x,@ \\
     279$\triangleright$ & pointer to value & @T *@ & @T x[10],@ & @[10] T x,@ \\
     280        & & & @T x[],@ & @[] T x,@ \\
     281        \hline
     282        & & & @T * const x,@ & @const * T x@ \\
     283        & immutable ptr.\ to val. & @T * const@ & @T x[const 10],@ & @[const 10] T x,@ \\
     284        & & & @T x[const],@ & @[const] T x,@\\
     285        \hline
     286        & & & @const T * x,@ & @ * const T x,@ \\
     287        & &     & @T const * x,@ & @ * T const x,@ \\
     288        & ptr.\ to immutable val. & @const T *@ & @const T x[10],@ & @[10] const T x,@ \\
     289        & & @T const *@ & @T const x[10],@ &  @[10] T const x,@ \\
     290        & & & @const T x[],@ & @[] const T x,@ \\
     291        & & & @T const x[],@ & @[] T const x,@ \\
     292        \hline \hline
     293        & & & @T (*x)[10],@ & @* [10] T x,@ \\
     294$\triangleright$ & ptr.\ to ar.\ of val. & @T(*)[10]@ & @T x[3][10],@ & @[3][10] T x,@ \\
     295        & & & @T x[][10],@ & @[][10] T x,@ \\
     296        \hline
     297        & & & @T ** x,@ & @** T x,@ \\
     298        & ptr.\ to ptr.\ to val. & @T **@ & @T * x[10],@ & @[10] * T x,@ \\
     299        & & & @T * x[],@ & @[] * T x,@ \\
     300        \hline
     301        & ptr.\ to ptr.\ to imm.\ val. & @const char **@ & @const char * argv[],@ & @[] * const char argv,@ \\
     302    & & & \emph{others elided} & \emph{others elided} \\
     303        \hline
    322304\end{tabular}
    323 \caption{Unfortunate Syntactic Reference for Decay during Parameter-Passing.  Includes interaction with constness, where ``no writing'' refers to a restriction on the callee's ability.}
    324 \label{bkgd:ar:usr:decay-parm}
    325 \end{figure}
     305\end{table}
    326306
    327307
    328308\subsection{Lengths may vary, checking does not}
    329309
    330 When the desired number of elements is unknown at compile time,
    331 a variable-length array is a solution:
    332 \begin{cfa}
    333 int main( int argc, const char *argv[] ) {
     310When the desired number of elements is unknown at compile time, a variable-length array is a solution:
     311\begin{cfa}
     312int main( int argc, const char * argv[] ) {
    334313        assert( argc == 2 );
    335314        size_t n = atol( argv[1] );
    336         assert( 0 < n && n < 1000 );
    337 
     315        assert( 0 < n );
    338316        float ar[n];
    339317        float b[10];
    340 
    341318        // ... discussion continues here
    342319}
    343320\end{cfa}
    344 This arrangement allocates @n@ elements on the @main@ stack frame for @ar@, just as it puts 10 elements on the @main@ stack frame for @b@.
    345 The variable-sized allocation of @ar@ is provided by @alloca@.
    346 
    347 In a situation where the array sizes are not known to be small enough for stack allocation to be sensible, corresponding heap allocations are achievable as:
    348 \begin{cfa}
    349 float *ax1 = malloc( sizeof( float[n] ) );
    350 float *ax2 = malloc( n * sizeof( float ) );
    351 float *bx1 = malloc( sizeof( float[1000000] ) );
    352 float *bx2 = malloc( 1000000 * sizeof( float ) );
    353 \end{cfa}
    354 
    355 
    356 VLA
     321This arrangement allocates @n@ elements on the @main@ stack frame for @ar@, called a \newterm{variable length array} (VLA), as well as 10 elements in the same stack frame for @b@.
     322The variable-sized allocation of @ar@ is provided by the @alloca@ routine, which bumps the stack pointer.
     323Note, the C standard supports VLAs~\cite[\S~6.7.6.2.4]{C11} as a conditional feature, but the \CC standard does not;
     324both @gcc@ and @g++@ support VLAs.
     325As well, there is misinformation about VLAs, \eg VLAs cause stack failures or are inefficient.
     326VLAs exist as far back as Algol W~\cite[\S~5.2]{AlgolW} and are a sound and efficient data type.
     327
     328For high-performance applications, the stack size can be fixed and small (coroutines or user-level threads).
     329Here, VLAs can overflow the stack, so a heap allocation is used.
     330\begin{cfa}
     331float * ax1 = malloc( sizeof( float[n] ) );
     332float * ax2 = malloc( n * sizeof( float ) );
     333float * bx1 = malloc( sizeof( float[1000000] ) );
     334float * bx2 = malloc( 1000000 * sizeof( float ) );
     335\end{cfa}
    357336
    358337Parameter dependency
     
    363342
    364343
    365 
    366 \subsection{C has full-service, dynamically sized, multidimensional arrays (and \CC does not)}
     344\subsection{Dynamically sized, multidimensional arrays}
    367345
    368346In C and \CC, ``multidimensional array'' means ``array of arrays.''  Other meanings are discussed in TODO.
     
    416394\section{Linked List}
    417395
     396Linked-lists are blocks of storage connected using one or more pointers.
     397The storage block is logically divided into data and links (pointers), where the links are the only component used by the list structure.
     398Since the data is opaque, list structures are often polymorphic over the data, which is normally homogeneous.
     399
    418400
    419401\section{String}
     402
     403A string is a logical sequence of symbols, where the form of the symbols can vary significantly: 7/8-bit characters (ASCII/Latin-1), or 2/4/8-byte (UNICODE) characters/symbols or variable length (UTF-8/16/32) characters.
     404A string can be read left-to-right, right-to-left, top-to-bottom, and have stacked elements (Arabic).
     405
     406An integer character constant is a sequence of one or more multibyte characters enclosed in single-quotes, as in @'x'@.
     407A wide character constant is the same, except prefixed by the letter @L@, @u@, or @U@.
     408With a few exceptions detailed later, the elements of the sequence are any members of the source character set;
     409they are mapped in an implementation-defined manner to members of the execution character set.
     410
     411A C character-string literal is a sequence of zero or more multibyte characters enclosed in double-quotes, as in @"xyz"@.
     412A UTF-8 string literal is the same, except prefixed by @u8@.
     413A wide string literal is the same, except prefixed by the letter @L@, @u@, or @U@.
     414
     415For UTF-8 string literals, the array elements have type @char@, and are initialized with the characters of the multibyte character sequence, as encoded in UTF-8.
     416For wide string literals prefixed by the letter @L@, the array elements have type @wchar_t@ and are initialized with the sequence of wide characters corresponding to the multibyte character sequence, as defined by the @mbstowcs@ function with an implementation-defined current locale.
     417For wide string literals prefixed by the letter @u@ or @U@, the array elements have type @char16_t@ or @char32_t@, respectively, and are initialized with the sequence of wide characters corresponding to the multibyte character sequence, as defined by successive calls to the @mbrtoc16@, or @mbrtoc32@ function as appropriate for its type, with an implementation-defined current locale.
     418The value of a string literal containing a multibyte character or escape sequence not represented in the executioncharacter set is implementation-defined.
     419
     420
     421Another bad C design decision is to have null-terminated strings rather than maintaining a separate string length.
     422\begin{quote}
     423Technically, a string is an array whose elements are single characters.
     424The compiler automatically places the null character @\0@ at the end of each such string, so programs can conveniently find the end.
     425This representation means that there is no real limit to how long a string can be, but programs have to scan one completely to determine its length.
     426\end{quote}
  • doc/theses/mike_brooks_MMath/programs/bkgd-carray-arrty.c

    raf746cc rdc58e5d  
    5757        f( &ar );
    5858
    59         float fs[] = {3.14, 1.707};
     59        float fs[] = {3.14, 1.77};
    6060        char cs[] = "hello";
    6161        static_assert( sizeof(fs) == 2 * sizeof(float) );
    6262        static_assert( sizeof(cs) == 6 * sizeof(char) );  $\C{// 5 letters + 1 null terminator}$
    6363
     64        float fm[][2] = { {3.14, 1.77}, {12.4, 0.01}, {7.8, 1.23} };  $\C{// brackets define structuring}$
     65        char cm[][sizeof("hello")] = { "hello", "hello", "hello" };
     66        static_assert( sizeof(fm) == 3 * 2 * sizeof(float) );
     67        static_assert( sizeof(cm) == 3 * 6 * sizeof(char) );
    6468}
    6569
  • doc/theses/mike_brooks_MMath/programs/bkgd-carray-decay.c

    raf746cc rdc58e5d  
    44        float (*pa)[10] = &a;           $\C{// pointer to array}$
    55        float a0 = a[0];                        $\C{// element}$
    6         float *pa0 = &(a[0]);           $\C{// pointer to element}$
     6        float * pa0 = &(a[0]);          $\C{// pointer to element}$
    77
    8         float *pa0x = a;                        $\C{// (ok)}$
     8        float * pa0x = a;                       $\C{// (ok)}$
    99        assert( pa0 == pa0x );
    1010        assert( sizeof(pa0x) != sizeof(a) );
    1111
    12         void f( float x[10], float *y ) {
    13                 static_assert( sizeof(x) == sizeof(void*) );
    14                 static_assert( sizeof(y) == sizeof(void*) );
     12        void f( float x[10], float * y ) {
     13                static_assert( sizeof(x) == sizeof(void *) );
     14                static_assert( sizeof(y) == sizeof(void *) );
    1515        }
    1616        f(0,0);
     
    2222
    2323        char ca[] = "hello";            $\C{// array on stack, initialized from read-only data}$
    24         char *cp = "hello";                     $\C{// pointer to read-only data [decay here]}$
    25         void edit( char c[] ) {         $\C{// param is pointer}$
     24        char * cp = "hello";            $\C{// pointer to read-only data [decay here]}$
     25        void edit( char c[] ) {         $\C{// parameter is pointer}$
    2626                c[3] = 'p';
    2727        }
    2828        edit( ca );                                     $\C{// ok [decay here]}$
    29         edit( c p );                            $\C{// Segmentation fault}$
     29        edit( cp );                                     $\C{// Segmentation fault}$
    3030        edit( "hello" );                        $\C{// Segmentation fault [decay here]}$
    3131
    3232        void decay( float x[10] ) {
    33                 static_assert( sizeof(x) == sizeof(void*) );
     33                static_assert( sizeof(x) == sizeof(void *) );
    3434        }
    3535        static_assert( sizeof(a) == 10 * sizeof(float) );
  • libcfa/src/concurrency/kernel/cluster.cfa

    raf746cc rdc58e5d  
    341341        // Make sure that everything is consistent
    342342        /* paranoid */ check_readyQ( cltr );
    343         /* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) );
     343//      /* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) );
    344344
    345345        __cfadbg_print_safe(ready_queue, "Kernel : Growing ready queue done\n");
     
    416416                fix_times(readyQ.tscs, ncount);
    417417        }
     418
    418419        cltr->sched.caches = alloc( target, cltr->sched.caches`realloc );
    419420
     
    428429
    429430        // Make sure that everything is consistent
    430         /* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) );
     431//      /* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) );
    431432        /* paranoid */ check_readyQ( cltr );
    432433
  • libcfa/src/concurrency/kernel/startup.cfa

    raf746cc rdc58e5d  
    672672        uint_fast32_t last_size = ready_mutate_lock();
    673673
    674                 // Adjust the ready queue size
    675                 ready_queue_shrink( &this );
     674        // Adjust the ready queue size
     675        ready_queue_shrink( &this );
    676676
    677677        // Unlock the RWlock
     
    682682        /* paranoid */ verify( this.sched.readyQ.tscs == 0p );
    683683        /* paranoid */ verify( this.sched.readyQ.count == 0 );
    684         /* paranoid */ verify( this.sched.io.tscs == 0p );
    685         /* paranoid */ verify( this.sched.caches == 0p );
     684//      /* paranoid */ verify( this.sched.io.tscs == 0p );
     685//      /* paranoid */ verify( this.sched.caches == 0p );
    686686
    687687        enable_interrupts( false ); // Don't poll, could be in main cluster
  • libcfa/src/heap.cfa

    raf746cc rdc58e5d  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jan  3 21:30:54 2024
    13 // Update Count     : 1619
     12// Last Modified On : Sun Apr  7 21:54:29 2024
     13// Update Count     : 1644
    1414//
    1515
     
    114114
    115115
    116 // generic Bsearchl does not inline, so substitute with hand-coded binary-search.
     116// CFA generic Bsearchl does not inline, so substitute with hand-coded binary-search.
    117117inline __attribute__((always_inline))
    118118static size_t Bsearchl( unsigned int key, const unsigned int vals[], size_t dim ) {
     
    190190                unsigned int realloc_calls, realloc_0_calls;
    191191                unsigned long long int realloc_storage_request, realloc_storage_alloc;
    192                 unsigned int free_calls, free_null_calls;
     192                unsigned int free_calls, free_null_0_calls;
    193193                unsigned long long int free_storage_request, free_storage_alloc;
    194194                unsigned int return_pulls, return_pushes;
     
    232232                struct Header {                                                                 // header
    233233                        union Kind {
    234                                 struct RealHeader {
     234                                struct RealHeader {                                             // 4-byte word => 8-byte header, 8-byte word => 16-byte header
    235235                                        union {
    236                                                 struct {                                                // 4-byte word => 8-byte header, 8-byte word => 16-byte header
    237                                                         union {
    238                                                                 // 2nd low-order bit => zero filled, 3rd low-order bit => mmapped
    239                                                                 // FreeHeader * home;           // allocated block points back to home locations (must overlay alignment)
    240                                                                 void * home;                    // allocated block points back to home locations (must overlay alignment)
    241                                                                 size_t blockSize;               // size for munmap (must overlay alignment)
    242                                                                 Storage * next;                 // freed block points to next freed block of same size
    243                                                         };
    244                                                         size_t size;                            // allocation size in bytes
    245                                                 };
     236                                                // 2nd low-order bit => zero filled, 3rd low-order bit => mmapped
     237                                                // FreeHeader * home;                   // allocated block points back to home locations (must overlay alignment)
     238                                                void * home;                                    // allocated block points back to home locations (must overlay alignment)
     239                                                size_t blockSize;                               // size for munmap (must overlay alignment)
     240                                                Storage * next;                                 // freed block points to next freed block of same size
    246241                                        };
     242                                        size_t size;                                            // allocation size in bytes
    247243                                } real; // RealHeader
    248244
     
    261257
    262258        struct CALIGN FreeHeader {
    263                 size_t blockSize CALIGN;                                                // size of allocations on this list
    264259                #ifdef OWNERSHIP
    265260                #ifdef RETURNSPIN
     
    271266                Storage * freeList;                                                             // thread free list
    272267                Heap * homeManager;                                                             // heap owner (free storage to bucket, from bucket to heap)
     268                size_t blockSize;                                                               // size of allocations on this list
    273269        }; // FreeHeader
    274270
     
    369365static __thread size_t PAD1 CALIGN TLSMODEL __attribute__(( unused )); // protect false sharing
    370366static __thread Heap * heapManager CALIGN TLSMODEL;
    371 static  __thread bool heapManagerBootFlag CALIGN TLSMODEL = false;
     367static __thread bool heapManagerBootFlag CALIGN TLSMODEL = false;
    372368static __thread size_t PAD2 CALIGN TLSMODEL __attribute__(( unused )); // protect further false sharing
    373369
     
    595591
    596592#ifdef __STATISTICS__
    597 static HeapStatistics stats;                                                    // zero filled
    598 
    599593#define prtFmt \
    600594        "\nHeap statistics: (storage request / allocation)\n" \
     
    607601        "  resize    >0 calls %'u; 0 calls %'u; storage %'llu / %'llu bytes\n" \
    608602        "  realloc   >0 calls %'u; 0 calls %'u; storage %'llu / %'llu bytes\n" \
    609         "  free      !null calls %'u; null calls %'u; storage %'llu / %'llu bytes\n" \
     603        "  free      !null calls %'u; null/0 calls %'u; storage %'llu / %'llu bytes\n" \
    610604        "  return    pulls %'u; pushes %'u; storage %'llu / %'llu bytes\n" \
    611605        "  sbrk      calls %'u; storage %'llu bytes\n" \
     
    627621                        resize_calls, resize_0_calls, resize_storage_request, resize_storage_alloc,
    628622                        realloc_calls, realloc_0_calls, realloc_storage_request, realloc_storage_alloc,
    629                         free_calls, free_null_calls, free_storage_request, free_storage_alloc,
     623                        free_calls, free_null_0_calls, free_storage_request, free_storage_alloc,
    630624                        return_pulls, return_pushes, return_storage_request, return_storage_alloc,
    631625                        sbrk_calls, sbrk_storage,
     
    650644        "<total type=\"resize\" >0 count=\"%'u;\" 0 count=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
    651645        "<total type=\"realloc\" >0 count=\"%'u;\" 0 count=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
    652         "<total type=\"free\" !null=\"%'u;\" 0 null=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
     646        "<total type=\"free\" !null=\"%'u;\" 0 null/0=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
    653647        "<total type=\"return\" pulls=\"%'u;\" 0 pushes=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
    654648        "<total type=\"sbrk\" count=\"%'u;\" size=\"%'llu\"/> bytes\n" \
     
    670664                        resize_calls, resize_0_calls, resize_storage_request, resize_storage_alloc,
    671665                        realloc_calls, realloc_0_calls, realloc_storage_request, realloc_storage_alloc,
    672                         free_calls, free_null_calls, free_storage_request, free_storage_alloc,
     666                        free_calls, free_null_0_calls, free_storage_request, free_storage_alloc,
    673667                        return_pulls, return_pushes, return_storage_request, return_storage_alloc,
    674668                        sbrk_calls, sbrk_storage,
     
    799793        } else {
    800794                fakeHeader( header, alignment );
    801                 if ( unlikely( MmappedBit( header ) ) ) {               // mmapped ?
     795                if ( unlikely( MmappedBit( header ) ) ) {               // mmapped storage ?
    802796                        verify( addr < heapBegin || heapEnd < addr );
    803797                        size = ClearStickyBits( header->kind.real.blockSize ); // mmap size
     798                        freeHead = 0p;                                                          // prevent uninitialized warning
    804799                        return true;
    805800                } // if
     
    904899
    905900
    906 #define BOOT_HEAP_MANAGER \
    907         if ( unlikely( ! heapMasterBootFlag ) ) { \
    908                 heapManagerCtor(); /* trigger for first heap */ \
    909         } /* if */
    910 
    911901#ifdef __STATISTICS__
    912902#define STAT_NAME __counter
    913903#define STAT_PARM , unsigned int STAT_NAME
    914904#define STAT_ARG( name ) , name
    915 #define STAT_0_CNT( counter ) stats.counters[counter].calls_0 += 1
     905#define STAT_0_CNT( counter ) heapManager->stats.counters[counter].calls_0 += 1
    916906#else
    917907#define STAT_NAME
     
    921911#endif // __STATISTICS__
    922912
    923 // Uncomment to get allocation addresses for a 0-sized allocation rather than a null pointer.
    924 //#define __NONNULL_0_ALLOC__
    925 #if ! defined( __NONNULL_0_ALLOC__ )
    926 #define __NULL_0_ALLOC__ unlikely( size == 0 ) ||               /* 0 BYTE ALLOCATION RETURNS NULL POINTER */
     913#define BOOT_HEAP_MANAGER \
     914        if ( unlikely( ! heapMasterBootFlag ) ) { \
     915                heapManagerCtor(); /* trigger for first heap */ \
     916        } /* if */ \
     917        verify( heapManager );
     918
     919#define __NONNULL_0_ALLOC__ /* Uncomment to return non-null address for malloc( 0 ). */
     920#ifndef __NONNULL_0_ALLOC__
     921#define __NULL_0_ALLOC__( counter, ... ) /* 0 byte allocation returns null pointer */ \
     922        if ( unlikely( size == 0 ) ) { \
     923                STAT_0_CNT( counter ); \
     924                __VA_ARGS__; /* call routine, if specified */ \
     925                return 0p; \
     926        } /* if */
    927927#else
    928 #define __NULL_0_ALLOC__
     928#define __NULL_0_ALLOC__( counter, ... )
    929929#endif // __NONNULL_0_ALLOC__
     930
     931#ifdef __DEBUG__
     932#define __OVERFLOW_MALLOC__( ... ) \
     933        if ( unlikely( size > ULONG_MAX - sizeof(Heap.Storage) ) ) { /* error check */ \
     934                __VA_ARGS__; /* call routine, if specified */ \
     935                return 0p; \
     936        } /* if */
     937#else
     938#define __OVERFLOW_MALLOC__( ... )
     939#endif // __DEBUG__
    930940
    931941#define PROLOG( counter, ... ) \
    932942        BOOT_HEAP_MANAGER; \
    933         if ( \
    934                 __NULL_0_ALLOC__ \
    935                 unlikely( size > ULONG_MAX - sizeof(Heap.Storage) ) ) { /* error check */ \
    936                 STAT_0_CNT( counter ); \
    937                 __VA_ARGS__; \
    938                 return 0p; \
    939         } /* if */
    940 
     943        __NULL_0_ALLOC__( counter, __VA_ARGS__ ) \
     944        __OVERFLOW_MALLOC__( __VA_ARGS__ )
    941945
    942946#define SCRUB_SIZE 1024lu
     
    948952        PROLOG( STAT_NAME );
    949953
    950         verify( heapManager );
    951954        Heap.Storage * block;                                                           // pointer to new block of storage
    952955
     
    956959
    957960        #ifdef __STATISTICS__
    958         stats.counters[STAT_NAME].calls += 1;
     961        #ifdef __NONNULL_0_ALLOC__
     962        if ( unlikely( size == 0 ) )                                            // malloc( 0 ) ?
     963                stats.counters[STAT_NAME].calls_0 += 1;
     964        else
     965        #endif // __NONNULL_0_ALLOC__
     966                stats.counters[STAT_NAME].calls += 1;
    959967        stats.counters[STAT_NAME].request += size;
    960968        #endif // __STATISTICS__
     
    10781086
    10791087static void doFree( void * addr ) libcfa_nopreempt with( *heapManager ) {
     1088        // char buf[64];
     1089        // int len = sprintf( buf, "doFree addr %p\n", addr );
     1090        // write( 2, buf, len );
     1091
    10801092        verify( addr );
    10811093
     
    10911103        #endif // __STATISTICS__ || __CFA_DEBUG__
    10921104
     1105        // Do not move these down because heap can be null!
    10931106        #ifdef __STATISTICS__
     1107        #ifdef __NONNULL_0_ALLOC__
     1108        if ( unlikely( rsize == 0 ) )                                           // malloc( 0 ) ?
     1109                stats.free_null_0_calls += 1;
     1110        else
     1111        #endif // __NONNULL_0_ALLOC__
     1112                heapManager->stats.free_calls += 1;                             // count free amd implicit frees from resize/realloc
    10941113        stats.free_storage_request += rsize;
    10951114        stats.free_storage_alloc += size;
     
    11171136                } // if
    11181137        } else {
     1138                assert( freeHead );
    11191139                #ifdef __CFA_DEBUG__
    11201140                // memset is NOT always inlined!
     
    13211341        // call to malloc(), alloc(), calloc() or realloc(). If the area pointed to was moved, a free(oaddr) is done.
    13221342        void * resize( void * oaddr, size_t size ) libcfa_public {
    1323           if ( unlikely( oaddr == 0p ) ) {                              // => malloc( size )
     1343          if ( unlikely( oaddr == 0p ) ) {                                      // => malloc( size )
    13241344                        return doMalloc( size STAT_ARG( RESIZE ) );
    13251345                } // if
     
    13331353
    13341354                size_t odsize = DataStorage( bsize, oaddr, header ); // data storage available in bucket
    1335                 // same size, DO NOT preserve STICKY PROPERTIES.
     1355                // same size, DO NOT PRESERVE STICKY PROPERTIES.
    13361356                if ( oalign == libAlign() && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
    13371357                        ClearZeroFillBit( header );                                     // no alignment and turn off 0 fill
     
    13461366                } // if
    13471367
    1348                 // change size, DO NOT preserve STICKY PROPERTIES.
     1368                // change size, DO NOT PRESERVE STICKY PROPERTIES.
    13491369                doFree( oaddr );                                                                // free previous storage
    13501370
     
    13561376        // the old and new sizes.
    13571377        void * realloc( void * oaddr, size_t size ) libcfa_public {
     1378                // char buf[64];
     1379                // int len = sprintf( buf, "realloc1 oaddr %p size %d\n", oaddr, size );
     1380                // write( 2, buf, len );
    13581381          if ( unlikely( oaddr == 0p ) ) {                                      // => malloc( size )
    13591382                  return doMalloc( size STAT_ARG( REALLOC ) );
     
    14981521                } // if
    14991522
    1500                 #ifdef __STATISTICS__
    1501                 incCalls( FREE );
    1502                 #endif // __STATISTICS__
    1503 
    15041523                doFree( addr );                                                                 // handles heapManager == nullptr
    15051524        } // free
     
    15791598                #endif // __STATISTICS__
    15801599        } // malloc_stats_clear
    1581 
    15821600
    15831601        // Changes the file descriptor where malloc_stats() writes statistics.
     
    17001718        } // if
    17011719
    1702         // change size, DO NOT preserve STICKY PROPERTIES.
     1720        // change size, DO NOT PRESERVE STICKY PROPERTIES.
    17031721        doFree( oaddr );                                                                        // free previous storage
    17041722        return memalignNoStats( nalign, size STAT_ARG( RESIZE ) ); // create new aligned area
     
    17071725
    17081726void * realloc( void * oaddr, size_t nalign, size_t size ) libcfa_public {
     1727        // char buf[64];
     1728        // int len = sprintf( buf, "realloc2 oaddr %p size %d\n", oaddr, size );
     1729        // write( 2, buf, len );
    17091730  if ( unlikely( oaddr == 0p ) ) {                                              // => malloc( size )
    17101731                return memalignNoStats( nalign, size STAT_ARG( REALLOC ) );
  • libcfa/src/heap.hfa

    raf746cc rdc58e5d  
    1010// Created On       : Tue May 26 11:23:55 2020
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Sep 11 11:18:18 2023
    13 // Update Count     : 24
     12// Last Modified On : Mon Apr  1 09:36:20 2024
     13// Update Count     : 25
    1414//
    1515
     
    4646} // extern "C"
    4747
     48// New allocation operations.
    4849void * resize( void * oaddr, size_t alignment, size_t size );
    4950void * realloc( void * oaddr, size_t alignment, size_t size );
     
    5152
    5253// Local Variables: //
    53 // mode: c //
    5454// tab-width: 4 //
    5555// End: //
  • libcfa/src/stdlib.hfa

    raf746cc rdc58e5d  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Mar 17 08:25:31 2024
    13 // Update Count     : 796
     12// Last Modified On : Fri Apr 12 07:39:15 2024
     13// Update Count     : 812
    1414//
    1515
     
    109109        1. Replace the current forall-block that contains defintions of S_fill and S_realloc with following:
    110110                forall( T & | sized(T) ) {
    111                         union  U_fill           { char c; T * a; T t; };
    112                         struct S_fill           { char tag; U_fill(T) fill; };
    113                         struct S_realloc        { inline T *; };
     111                        union  U_fill { char c; T * a; T t; };
     112                        struct S_fill { char tag; U_fill(T) fill; };
     113                        struct S_realloc { inline T *; };
    114114                }
    115115
    116116        2. Replace all current postfix-fill functions with following for updated S_fill:
    117                 S_fill(T) ?`fill( char a )                                      { S_fill(T) ret = {'c'}; ret.fill.c = a; return ret; }
    118                 S_fill(T) ?`fill( T    a )                                      { S_fill(T) ret = {'t'}; memcpy(&ret.fill.t, &a, sizeof(T)); return ret; }
    119                 S_fill(T) ?`fill( T    a[], size_t nmemb )      { S_fill(T) ret = {'a', nmemb}; ret.fill.a = a; return ret; }
     117                S_fill(T) ?`fill( char a ) { S_fill(T) ret = {'c'}; ret.fill.c = a; return ret; }
     118                S_fill(T) ?`fill( T a ) { S_fill(T) ret = {'t'}; memcpy(&ret.fill.t, &a, sizeof(T)); return ret; }
     119                S_fill(T) ?`fill( T a[], size_t nmemb ) { S_fill(T) ret = {'a', nmemb}; ret.fill.a = a; return ret; }
    120120
    121121        3. Replace the alloc_internal$ function which is outside ttype forall-block with following function:
     
    148148*/
    149149
    150 typedef struct S_align                  { inline size_t;  } T_align;
    151 typedef struct S_resize                 { inline void *;  }     T_resize;
     150typedef struct S_align { inline size_t;  } T_align;
     151typedef struct S_resize { inline void *;  }     T_resize;
    152152
    153153forall( T & ) {
    154         struct S_fill           { char tag; char c; size_t size; T * at; char t[50]; };
    155         struct S_realloc        { inline T *; };
     154        struct S_fill { char tag; char c; size_t size; T * at; char t[50]; };
     155        struct S_realloc { inline T *; };
    156156}
    157157
    158 static inline T_align   ?`align   ( size_t a )  { return (T_align){a}; }
    159 static inline T_resize  ?`resize  ( void * a )  { return (T_resize){a}; }
    160 
     158static inline T_align ?`align( size_t a ) { return (T_align){a}; }
     159static inline T_resize ?`resize( void * a )     { return (T_resize){a}; }
     160
     161extern "C" ssize_t write(int fd, const void *buf, size_t count);
    161162static inline forall( T & | sized(T) ) {
    162163        S_fill(T) ?`fill ( T t ) {
     
    169170                return ret;
    170171        }
    171         S_fill(T)               ?`fill ( zero_t ) = void; // FIX ME: remove this once ticket 214 is resolved
    172         S_fill(T)               ?`fill ( T * a )                                { return (S_fill(T)){ 'T', '0', 0, a }; } // FIX ME: remove this once ticket 214 is resolved
    173         S_fill(T)               ?`fill ( char c )                               { return (S_fill(T)){ 'c', c }; }
    174         S_fill(T)               ?`fill ( T a[], size_t nmemb )  { return (S_fill(T)){ 'a', '0', nmemb * sizeof(T), a }; }
    175 
    176         S_realloc(T)    ?`realloc ( T * a )                             { return (S_realloc(T)){a}; }
     172        S_fill(T) ?`fill ( zero_t ) = void; // FIX ME: remove this once ticket 214 is resolved
     173        S_fill(T) ?`fill ( T * a ) { return (S_fill(T)){ 'T', '0', 0, a }; } // FIX ME: remove this once ticket 214 is resolved
     174        S_fill(T) ?`fill ( char c ) { return (S_fill(T)){ 'c', c };     }
     175        S_fill(T) ?`fill ( T a[], size_t nmemb ) { return (S_fill(T)){ 'a', '0', nmemb * sizeof(T), a }; }
     176
     177        S_realloc(T) ?`realloc ( T * a ) { return (S_realloc(T)){a}; }
    177178
    178179        T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill ) {
     
    182183
    183184                if ( Resize ) {
    184                         ptr = (T*) (void *) resize( (void *)Resize, Align, Dim * size );
     185                        ptr = (T*)(void *)resize( (void *)Resize, Align, Dim * size );
    185186                } else if ( Realloc ) {
    186187                        if ( Fill.tag != '0' ) copy_end = min(malloc_size( Realloc ), Dim * size );
    187                         ptr = (T *) (void *) realloc( (void *)Realloc, Align, Dim * size );
     188                        ptr = (T *)(void *)realloc( (void *)Realloc, Align, Dim * size );
    188189                } else {
    189                         ptr = (T *) (void *) memalign( Align, Dim * size );
     190                        ptr = (T *)(void *) memalign( Align, Dim * size );
    190191                }
    191192
  • src/AST/Pass.hpp

    raf746cc rdc58e5d  
    252252private:
    253253
    254         __pass::result1<ast::Stmt> call_accept( const ast::Stmt * );
    255         __pass::result1<ast::Expr> call_accept( const ast::Expr * );
    256 
    257         /// This has a `type` member that is the return type for the
    258         /// generic call_accept if the generic call_accept is defined.
     254        /// The return type of the general call_accept function.
    259255        template< typename node_t >
    260         using generic_call_accept_result =
    261                 std::enable_if<
    262                                 !std::is_base_of<ast::Expr, node_t>::value &&
    263                                 !std::is_base_of<ast::Stmt, node_t>::value
    264                         , __pass::result1<
    265                                 typename std::remove_pointer< typename std::result_of<
    266                                         decltype(&node_t::accept)(node_t*, type&) >::type >::type
    267                         >
     256        using call_accept_result_t = __pass::result1<
     257                typename std::remove_pointer< typename std::result_of<
     258                        decltype(&node_t::accept)(node_t*, type&) >::type >::type
    268259                >;
    269260
    270261        template< typename node_t >
    271         auto call_accept( const node_t * node )
    272                 -> typename generic_call_accept_result<node_t>::type;
     262        auto call_accept( const node_t * node ) -> call_accept_result_t<node_t>;
    273263
    274264        // requests WithStmtsToAdd directly add to this statement, as if it is a compound.
  • src/AST/Pass.impl.hpp

    raf746cc rdc58e5d  
    109109                return val;
    110110        }
    111 
    112         //------------------------------
    113         /// Check if value was mutated, different for pointers and containers
    114         template<typename lhs_t, typename rhs_t>
    115         bool differs( const lhs_t * old_val, const rhs_t * new_val ) {
    116                 return old_val != new_val;
    117         }
    118 
    119         template< template <class...> class container_t, typename node_t >
    120         bool differs( const container_t<ast::ptr< node_t >> &, const container_t<ast::ptr< node_t >> & new_val ) {
    121                 return !new_val.empty();
    122         }
    123111}
    124112
     
    126114template< typename node_t >
    127115auto ast::Pass< core_t >::call_accept( const node_t * node ) ->
    128         typename ast::Pass< core_t >::template generic_call_accept_result<node_t>::type
    129 {
     116                ast::Pass< core_t >::call_accept_result_t<node_t> {
    130117        __pedantic_pass_assert( __visit_children() );
    131118        __pedantic_pass_assert( node );
    132119
    133         static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR" );
    134         static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR" );
    135 
    136120        auto nval = node->accept( *this );
    137         __pass::result1<
    138                 typename std::remove_pointer< decltype( node->accept(*this) ) >::type
    139         > res;
    140         res.differs = nval != node;
    141         res.value = nval;
    142         return res;
    143 }
    144 
    145 template< typename core_t >
    146 ast::__pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept( const ast::Expr * expr ) {
    147         __pedantic_pass_assert( __visit_children() );
    148         __pedantic_pass_assert( expr );
    149 
    150         auto nval = expr->accept( *this );
    151         return { nval != expr, nval };
    152 }
    153 
    154 template< typename core_t >
    155 ast::__pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) {
    156         __pedantic_pass_assert( __visit_children() );
    157         __pedantic_pass_assert( stmt );
    158 
    159         const ast::Stmt * nval = stmt->accept( *this );
    160         return { nval != stmt, nval };
     121        return { nval != node, nval };
    161122}
    162123
     
    230191ast::__pass::template resultNstmt<container_t> ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
    231192        __pedantic_pass_assert( __visit_children() );
    232         if ( statements.empty() ) return {};
     193        __pedantic_pass_assert( !statements.empty() );
    233194
    234195        // We are going to aggregate errors for all these statements
     
    263224                        const ast::Stmt * new_stmt = stmt->accept( *this );
    264225                        assert( new_stmt );
    265                         if ( new_stmt != stmt ) { new_kids.differs = true; }
    266226
    267227                        // Make sure that it is either adding statements or declartions but not both
     
    276236                        // Now add the statement if there is one
    277237                        if ( new_stmt != stmt ) {
    278                                 new_kids.values.emplace_back( new_stmt, i, false );
     238                                new_kids.differs = true;
     239                                new_kids.values.emplace_back( new_stmt );
    279240                        } else {
    280                                 new_kids.values.emplace_back( nullptr, i, true );
     241                                new_kids.values.emplace_back( i );
    281242                        }
    282243
     
    298259ast::__pass::template resultN<container_t, node_t> ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
    299260        __pedantic_pass_assert( __visit_children() );
    300         if ( container.empty() ) return {};
     261        __pedantic_pass_assert( !container.empty() );
     262
     263        // Collect errors from processing all these nodes.
    301264        SemanticErrorException errors;
    302265
     
    342305        static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
    343306
    344         auto new_val = call_accept( old_val );
    345 
    346         static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR" );
    347 
    348         if ( new_val.differs ) {
     307        auto result = call_accept( old_val );
     308        if ( result.differs ) {
    349309                auto new_parent = __pass::mutate<core_t>(parent);
    350                 new_val.apply(new_parent, field);
     310                result.apply( new_parent, field );
    351311                parent = new_parent;
    352312        }
     
    366326        static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
    367327
    368         auto new_val = call_accept_top( old_val );
    369 
    370         static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR" );
    371 
    372         if ( new_val.differs ) {
     328        auto result = call_accept_top( old_val );
     329        if ( result.differs ) {
    373330                auto new_parent = __pass::mutate<core_t>(parent);
    374                 new_val.apply(new_parent, field);
     331                result.apply( new_parent, field );
    375332                parent = new_parent;
    376333        }
     
    390347        static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
    391348
    392         auto new_val = call_accept_as_compound( old_val );
    393 
    394         static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR" );
    395 
    396         if ( new_val.differs ) {
     349        auto result = call_accept_as_compound( old_val );
     350        if ( result.differs ) {
    397351                auto new_parent = __pass::mutate<core_t>(parent);
    398                 new_val.apply( new_parent, child );
     352                result.apply( new_parent, child );
    399353                parent = new_parent;
    400354        }
     
    452406template< typename core_t >
    453407inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) {
    454         if ( auto ptr = __pass::translation_unit::get_cptr( visitor.core, 0 ) ) {
     408        if ( auto ptr = __pass::translationUnit( visitor.core, 0 ) ) {
    455409                ValueGuard<const TranslationUnit *> guard( *ptr );
    456410                *ptr = &unit;
  • src/AST/Pass.proto.hpp

    raf746cc rdc58e5d  
    154154                bool is_old;
    155155
    156                 delta(const Stmt * s, ssize_t i, bool old) :
    157                         new_val(s), old_idx(i), is_old(old) {}
     156                explicit delta(const Stmt * s) : new_val(s), old_idx(-1), is_old(false) {}
     157                explicit delta(ssize_t i) : new_val(nullptr), old_idx(i), is_old(true) {}
    158158        };
    159159
     
    188188                std::transform( stmts->begin(), stmts->end(), std::back_inserter( values ),
    189189                        [](ast::ptr<ast::Stmt>& stmt) -> delta {
    190                                 return delta( stmt.release(), -1, false );
     190                                return delta( stmt.release() );
    191191                        });
    192192                stmts->clear();
     
    201201                        [](ast::ptr<ast::Decl>& decl) -> delta {
    202202                                ast::Decl const * d = decl.release();
    203                                 return delta( new DeclStmt( d->location, d ), -1, false );
     203                                return delta( new DeclStmt( d->location, d ) );
    204204                        });
    205205                decls->clear();
     
    226226                // Now the original containers should still have the unchanged values
    227227                // but also contain the new values.
    228         }
    229 };
    230 
    231 /// Used by previsit implementation
    232 /// We need to reassign the result to 'node', unless the function
    233 /// returns void, then we just leave 'node' unchanged
    234 template<bool is_void>
    235 struct __assign;
    236 
    237 template<>
    238 struct __assign<true> {
    239         template<typename core_t, typename node_t>
    240         static inline void result( core_t & core, const node_t * & node ) {
    241                 core.previsit( node );
    242         }
    243 };
    244 
    245 template<>
    246 struct __assign<false> {
    247         template<typename core_t, typename node_t>
    248         static inline void result( core_t & core, const node_t * & node ) {
    249                 node = core.previsit( node );
    250                 assertf(node, "Previsit must not return NULL");
    251         }
    252 };
    253 
    254 /// Used by postvisit implementation
    255 /// We need to return the result unless the function
    256 /// returns void, then we just return the original node
    257 template<bool is_void>
    258 struct __return;
    259 
    260 template<>
    261 struct __return<true> {
    262         template<typename core_t, typename node_t>
    263         static inline const node_t * result( core_t & core, const node_t * & node ) {
    264                 core.postvisit( node );
    265                 return node;
    266         }
    267 };
    268 
    269 template<>
    270 struct __return<false> {
    271         template<typename core_t, typename node_t>
    272         static inline auto result( core_t & core, const node_t * & node ) {
    273                 return core.postvisit( node );
    274228        }
    275229};
     
    297251        );
    298252
    299         __assign<
    300                 std::is_void<
    301                         decltype( core.previsit( node ) )
    302                 >::value
    303         >::result( core, node );
     253        // We need to reassign the result to 'node', unless the function
     254        // returns void, then we just leave 'node' unchanged
     255        if constexpr ( std::is_void_v<decltype( core.previsit( node ) )> ) {
     256                core.previsit( node );
     257        } else {
     258                node = core.previsit( node );
     259                assertf( node, "Previsit must not return nullptr." );
     260        }
    304261}
    305262
     
    312269        decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
    313270{
    314         return __return<
    315                 std::is_void<
    316                         decltype( core.postvisit( node ) )
    317                 >::value
    318         >::result( core, node );
     271        // We need to return the result unless the function
     272        // returns void, then we just return the original node
     273        if constexpr ( std::is_void_v<decltype( core.postvisit( node ) )> ) {
     274                core.postvisit( node );
     275                return node;
     276        } else {
     277                return core.postvisit( node );
     278        }
    319279}
    320280
     
    350310FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
    351311FIELD_PTR( visitor, ast::Pass<core_t> * const )
     312FIELD_PTR( translationUnit, const TranslationUnit * )
    352313
    353314// Remove the macro to make sure we don't clash
     
    546507} // namespace forall
    547508
    548 // For passes that need access to the global context. Searches `translationUnit`
    549 namespace translation_unit {
    550         template<typename core_t>
    551         static inline auto get_cptr( core_t & core, int )
    552                         -> decltype( &core.translationUnit ) {
    553                 return &core.translationUnit;
    554         }
    555 
    556         template<typename core_t>
    557         static inline const TranslationUnit ** get_cptr( core_t &, long ) {
    558                 return nullptr;
    559         }
    560 }
    561 
    562509// For passes, usually utility passes, that have a result.
    563510namespace result {
  • src/Parser/StatementNode.cc

    raf746cc rdc58e5d  
    122122        ast::Expr * cond = nullptr;
    123123        if ( ctl->condition ) {
    124                 // compare the provided condition against 0
    125                 cond = notZeroExpr( maybeMoveBuild( ctl->condition ) );
     124                cond = maybeMoveBuild( ctl->condition );
    126125        } else {
    127126                for ( ast::ptr<ast::Stmt> & stmt : inits ) {
     
    129128                        auto declStmt = stmt.strict_as<ast::DeclStmt>();
    130129                        auto dwt = declStmt->decl.strict_as<ast::DeclWithType>();
    131                         ast::Expr * nze = notZeroExpr( new ast::VariableExpr( dwt->location, dwt ) );
     130                        ast::Expr * nze = new ast::VariableExpr( dwt->location, dwt );
    132131                        cond = cond ? new ast::LogicalExpr( dwt->location, cond, nze, ast::AndExpr ) : nze;
    133132                }
     
    200199        // do-while cannot have declarations in the contitional, so init is always empty
    201200        return new ast::WhileDoStmt( location,
    202                 notZeroExpr( maybeMoveBuild( ctl ) ),
     201                maybeMoveBuild( ctl ),
    203202                buildMoveSingle( stmt ),
    204203                buildMoveOptional( else_ ),
     
    213212
    214213        ast::Expr * astcond = nullptr;                                          // maybe empty
    215         astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) );
     214        astcond = maybeMoveBuild( forctl->condition );
    216215
    217216        ast::Expr * astincr = nullptr;                                          // maybe empty
     
    330329        clause->target = maybeBuild( targetExpr );
    331330        clause->stmt = maybeMoveBuild( stmt );
    332         clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
     331        clause->when_cond = maybeMoveBuild( when );
    333332
    334333        ExpressionNode * next = targetExpr->next;
     
    345344ast::WaitForStmt * build_waitfor_else( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt ) {
    346345        existing->else_stmt = maybeMoveBuild( stmt );
    347         existing->else_cond = notZeroExpr( maybeMoveBuild( when ) );
     346        existing->else_cond = maybeMoveBuild( when );
    348347
    349348        (void)location;
     
    354353        existing->timeout_time = maybeMoveBuild( timeout );
    355354        existing->timeout_stmt = maybeMoveBuild( stmt );
    356         existing->timeout_cond = notZeroExpr( maybeMoveBuild( when ) );
     355        existing->timeout_cond = maybeMoveBuild( when );
    357356
    358357        (void)location;
     
    362361ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
    363362        ast::WhenClause * clause = new ast::WhenClause( loc );
    364         clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
     363        clause->when_cond = maybeMoveBuild( when );
    365364        clause->stmt = maybeMoveBuild( stmt );
    366365        clause->target = maybeMoveBuild( targetExpr );
     
    369368ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation & loc, ExpressionNode * when, StatementNode * stmt ) {
    370369        ast::WhenClause * clause = new ast::WhenClause( loc );
    371         clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
     370        clause->when_cond = maybeMoveBuild( when );
    372371        clause->stmt = maybeMoveBuild( stmt );
    373372        return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause );
     
    508507
    509508        ast::Expr * astcond = nullptr;                                          // maybe empty
    510         astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) );
     509        astcond = maybeMoveBuild( forctl->condition );
    511510
    512511        ast::Expr * astincr = nullptr;                                          // maybe empty
  • src/Parser/module.mk

    raf746cc rdc58e5d  
    3131       Parser/parser.yy \
    3232       Parser/ParserTypes.h \
    33        Parser/parserutility.cc \
    3433       Parser/parserutility.h \
    3534       Parser/RunParser.cpp \
  • src/Parser/parserutility.h

    raf746cc rdc58e5d  
    1717
    1818#include "AST/Copy.hpp"            // for shallowCopy
    19 namespace ast {
    20         class Expr;
    21 }
    22 
    23 ast::Expr * notZeroExpr( const ast::Expr *orig );
    2419
    2520template< typename T >
  • src/ResolvExpr/CandidateFinder.cpp

    raf746cc rdc58e5d  
    4646#include "AST/Type.hpp"
    4747#include "Common/utility.h"       // for move, copy
    48 #include "Parser/parserutility.h" // for notZeroExpr
    4948#include "SymTab/Mangler.h"
    5049#include "Tuples/Tuples.h"        // for handleTupleAssignment
     
    15141513        void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) {
    15151514                CandidateFinder finder1( context, tenv );
    1516                 ast::ptr<ast::Expr> arg1 = notZeroExpr( logicalExpr->arg1 );
     1515                ast::ptr<ast::Expr> arg1 = createCondExpr( logicalExpr->arg1 );
    15171516                finder1.find( arg1, ResolveMode::withAdjustment() );
    15181517                if ( finder1.candidates.empty() ) return;
    15191518
    15201519                CandidateFinder finder2( context, tenv );
    1521                 ast::ptr<ast::Expr> arg2 = notZeroExpr( logicalExpr->arg2 );
     1520                ast::ptr<ast::Expr> arg2 = createCondExpr( logicalExpr->arg2 );
    15221521                finder2.find( arg2, ResolveMode::withAdjustment() );
    15231522                if ( finder2.candidates.empty() ) return;
     
    15451544        void Finder::postvisit( const ast::ConditionalExpr * conditionalExpr ) {
    15461545                // candidates for condition
    1547                 ast::ptr<ast::Expr> arg1 = notZeroExpr( conditionalExpr->arg1 );
     1546                ast::ptr<ast::Expr> arg1 = createCondExpr( conditionalExpr->arg1 );
    15481547                CandidateFinder finder1( context, tenv );
    15491548                finder1.find( arg1, ResolveMode::withAdjustment() );
     
    21662165                CandidateRef & choice = winners.front();
    21672166                return choice->expr;
    2168                 // return std::move( choice->expr.get() );
     2167}
     2168
     2169const ast::Expr * createCondExpr( const ast::Expr * expr ) {
     2170        assert( expr );
     2171        return new ast::CastExpr( expr->location,
     2172                ast::UntypedExpr::createCall( expr->location,
     2173                        "?!=?",
     2174                        {
     2175                                expr,
     2176                                new ast::ConstantExpr( expr->location,
     2177                                        new ast::ZeroType(), "0", std::make_optional( 0ull )
     2178                                ),
     2179                        }
     2180                ),
     2181                new ast::BasicType( ast::BasicType::SignedInt )
     2182        );
    21692183}
    21702184
  • src/ResolvExpr/CandidateFinder.hpp

    raf746cc rdc58e5d  
    7272const ast::Expr * getValueEnumCall(const ast::Expr * expr,
    7373        const ResolvExpr::ResolveContext & context, const ast::TypeEnvironment & env );
     74/// Wrap an expression to convert the result to a conditional result.
     75const ast::Expr * createCondExpr( const ast::Expr * expr );
    7476
    7577} // namespace ResolvExpr
  • src/ResolvExpr/Resolver.cc

    raf746cc rdc58e5d  
    340340        }
    341341
     342        ast::ptr< ast::Expr > findCondExpression(
     343                const ast::Expr * untyped, const ResolveContext & context
     344        ) {
     345                if ( nullptr == untyped ) return untyped;
     346                ast::ptr<ast::Expr> condExpr = createCondExpr( untyped );
     347                return findIntegralExpression( condExpr, context );
     348        }
     349
    342350        /// check if a type is a character type
    343351        bool isCharType( const ast::Type * t ) {
     
    356364                return it != end;
    357365        }
    358 }
     366} // anonymous namespace
    359367
    360368class Resolver final
     
    729737const ast::IfStmt * Resolver::previsit( const ast::IfStmt * ifStmt ) {
    730738        return ast::mutate_field(
    731                 ifStmt, &ast::IfStmt::cond, findIntegralExpression( ifStmt->cond, context ) );
     739                ifStmt, &ast::IfStmt::cond, findCondExpression( ifStmt->cond, context ) );
    732740}
    733741
    734742const ast::WhileDoStmt * Resolver::previsit( const ast::WhileDoStmt * whileDoStmt ) {
    735743        return ast::mutate_field(
    736                 whileDoStmt, &ast::WhileDoStmt::cond, findIntegralExpression( whileDoStmt->cond, context ) );
     744                whileDoStmt, &ast::WhileDoStmt::cond, findCondExpression( whileDoStmt->cond, context ) );
    737745}
    738746
     
    740748        if ( forStmt->cond ) {
    741749                forStmt = ast::mutate_field(
    742                         forStmt, &ast::ForStmt::cond, findIntegralExpression( forStmt->cond, context ) );
     750                        forStmt, &ast::ForStmt::cond, findCondExpression( forStmt->cond, context ) );
    743751        }
    744752
     
    10751083
    10761084                // Resolve the conditions as if it were an IfStmt, statements normally
    1077                 clause2->when_cond = findSingleExpression( clause.when_cond, context );
     1085                clause2->when_cond = findCondExpression( clause.when_cond, context );
    10781086                clause2->stmt = clause.stmt->accept( *visitor );
    10791087
     
    10891097                        new ast::BasicType{ ast::BasicType::LongLongUnsignedInt };
    10901098                auto timeout_time = findSingleExpression( stmt->timeout_time, target, context );
    1091                 auto timeout_cond = findSingleExpression( stmt->timeout_cond, context );
     1099                auto timeout_cond = findCondExpression( stmt->timeout_cond, context );
    10921100                auto timeout_stmt = stmt->timeout_stmt->accept( *visitor );
    10931101
     
    11021110        if ( stmt->else_stmt ) {
    11031111                // resolve the condition like IfStmt, stmts normally
    1104                 auto else_cond = findSingleExpression( stmt->else_cond, context );
     1112                auto else_cond = findCondExpression( stmt->else_cond, context );
    11051113                auto else_stmt = stmt->else_stmt->accept( *visitor );
    11061114
  • src/Validate/ImplementEnumFunc.cpp

    raf746cc rdc58e5d  
    516516    ast::EnumInstType enumInst(enumDecl->name);
    517517    enumInst.base = enumDecl;
    518     // ast::EnumAttrType attr = ast::EnumAttrType(&enumInst);
    519     // EnumAttrFuncGenerator gen(enumDecl, &enumInst functionNesting);
     518
    520519    EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
    521520    gen.generateAndAppendFunctions(declsToAddAfter);
Note: See TracChangeset for help on using the changeset viewer.