Changes in / [dc58e5d:af746cc]


Ignore:
Files:
1 added
18 edited

Legend:

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

    rdc58e5d raf746cc  
    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 by the type system.
    48 This 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 
    50 Continuing, a short form for declaring array variables exists using length information provided implicitly by an initializer.
     47So, 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.
     48This 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
     50Continuing, a shortened form for declaring local variables exists, provided that length information is given in the initializer:
    5151\lstinput{59-62}{bkgd-carray-arrty.c}
    52 The compiler counts the number of initializer elements and uses this value as the first dimension.
    53 Unfortunately, the implicit element counting does not extend to dimensions beyond the first.
    54 \lstinput{64-67}{bkgd-carray-arrty.c}
    55 
    56 My contribution is recognizing:
     52In these declarations, the resulting types are both arrays, but their lengths are inferred.
     53
     54My contribution is enabled by recognizing
    5755\begin{itemize}
    58         \item There is value in using a type that knows its size.
     56        \item There is value in using a type that knows how big the whole thing is.
    5957        \item The type pointer to (first) element does not.
    6058        \item C \emph{has} a type that knows the whole picture: 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.)}
     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]@.
    6560\end{itemize}
    6661
    67 
    68 \section{Reading Declarations}
    69 
    70 A 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}} \\
     62Each of these sections, which introduces another layer of of the C arrays' story,
     63concludes with an \emph{Unfortunate Syntactic Reference}.
     64It shows how to spell the types under discussion,
     65along with interactions with orthogonal (but easily confused) language features.
     66Alternate spellings are listed within a row.
     67The simplest occurrences of types distinguished in the preceding discussion are marked with $\triangleright$.
     68The 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).
     69The 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
     71After 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.
     75The \CFA-C column gives the, more fortunate, ``new'' syntax of section TODO, for spelling \emph{exactly the same type}.
     76This fortunate syntax does not have different spellings for types vs declarations;
     77a declaration is always the type followed by the declared identifier name;
     78for the example of letting @x@ be a \emph{pointer to array}, the declaration is spelled:
    7479\begin{cfa}
    75 int @(*@ar@)[@5@]@; // definition
    76   ... @(*@ar@)[@3@]@ += 1; // usage
     80[ * [10] T ] x;
    7781\end{cfa}
    78 &
    79 \begin{cfa}
    80 int @(*@f@())[@5@]@ { ... }; // definition
    81   ... @(*@f@())[@3@]@ += 1; // usage
    82 \end{cfa}
     82The \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}
     87\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
    83175\end{tabular}
    84 \end{cquote}
    85 Essentially, the type is wrapped around the name in successive layers (like an \Index{onion}).
    86 While 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}
    88 In 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}
    90 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!
    91 
    92 \CFA provides its own type, variable and routine declarations, using a simpler syntax.
    93 The new declarations place qualifiers to the left of the base type, while C declarations place qualifiers to the right of the base type.
    94 The qualifiers have the same meaning in \CFA as in C.
    95 Then, 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}
    100 int @*@ x1 @[5]@;
    101 int @(*@x2@)[5]@;
    102 int @(*@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}
    121 As declaration complexity increases, it becomes corresponding difficult to read and understand the C declaration form.
    122 Note, 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}.
    125 The \CFA-thesis column shows the new array declaration form, which is my contributed improvements for safety and ergonomics.
    126 The 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.
    127 Each row of the table shows alternate syntactic forms.
    128 The simplest occurrences of types distinguished in the preceding discussion are marked with $\triangleright$.
    129 Removing 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)}.
    130 Unfortunately, parameter declarations \PAB{(section TODO)} have more syntactic forms and rules.
    131 
    132 \begin{table}
    133 \centering
    134 \caption{Syntactic Reference for Array vs Pointer. Includes interaction with \lstinline{const}ness.}
     176\caption{Unfortunate Syntactic Reference for Array vs Pointer.  Includes interaction with constness.}
    135177\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
    175 \end{tabular}
    176 \end{table}
     178\end{figure}
     179
     180
     181
     182
    177183
    178184TODO: Address these parked unfortunate syntaxes
     
    180186        \item static
    181187        \item star as dimension
    182         \item under pointer decay: @int p1[const 3]@ being @int const *p1@
     188        \item under pointer decay:                              int p1[const 3]  being  int const *p1
    183189\end{itemize}
    184190
     
    197203\lstinput{10-10}{bkgd-carray-decay.c}
    198204
    199 So, C provides an implicit conversion from @float[10]@ to @float *@.
     205So, C provides an implicit conversion from @float[10]@ to @float*@, as described in ARM-6.3.2.1.3:
    200206\begin{quote}
    201 Except when it is the operand of the @sizeof@ operator, or the unary @&@ operator, or is a string literal used to
    202 initialize 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}
     207Except when it is the operand of the @sizeof@ operator, or the unary @&@ operator, or is a
     208string literal used to initialize an array
     209an expression that has type ``array of type'' is
     210converted to an expression with type ``pointer to type'' that points to the initial element of
     211the array object
    204212\end{quote}
     213
    205214This phenomenon is the famous ``pointer decay,'' which is a decay of an array-typed expression into a pointer-typed one.
     215
    206216It is worthy to note that the list of exception cases does not feature the occurrence of @ar@ in @ar[i]@.
    207 Thus, subscripting happens on pointers not arrays.
    208 
    209 Subscripting 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.
    211 Finally, \cite[\S~6.5.3.2.4]{C11} explains that the @*@ operator's result is the referenced element.
    212 Taken together, these rules illustrate that @ar[i]@ and @i[a]@ mean the same thing!
     217Thus, subscripting happens on pointers, not arrays.
     218
     219Subscripting 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)))@.
     220ARM-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.
     221Finally, ARM-6.5.3.2.4 explains that the @*@ operator's result is the referenced element.
     222
     223Taken together, these rules also happen to illustrate that @ar[i]@ and @i[a]@ mean the same thing.
    213224
    214225Subscripting a pointer when the target is standard-inappropriate is still practically well-defined.
     
    222233fs[5] = 3.14;
    223234\end{cfa}
    224 The @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}).
    225 But \emph{nothing} more is said about this pointer value, specifically that its referent might \emph{be} an array allowing subscripting.
    226 
    227 Under 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)@.
    228 I 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.
     235The @malloc@ behaviour is specified as returning a pointer to ``space for an object whose size is'' as requested (ARM-7.22.3.4.2).
     236But program says \emph{nothing} more about this pointer value, that might cause its referent to \emph{be} an array, before doing the subscript.
     237
     238Under this assumption, a pointer being subscripted (or added to, then dereferenced)
     239by any value (positive, zero, or negative), gives a view of the program's entire address space,
     240centred around the @p@ address, divided into adjacent @sizeof(*p)@ chunks,
     241each potentially (re)interpreted as @typeof(*p)@.
     242
     243I call this phenomenon ``array diffraction,''  which is a diffraction of a single-element pointer
     244into the assumption that its target is in the middle of an array whose size is unlimited in both directions.
     245
    229246No pointer is exempt from array diffraction.
     247
    230248No array shows its elements without pointer decay.
    231249
    232250A further pointer--array confusion, closely related to decay, occurs in parameter declarations.
    233 \cite[\S~6.7.6.3.7]{C11} explains that when an array type is written for a parameter,
    234 the parameter's type becomes a type that can be summarized as the array-decayed type.
    235 The respective handling of the following two parameter spellings shows that the array-spelled one is really, like the other, a pointer.
     251ARM-6.7.6.3.7 explains that when an array type is written for a parameter,
     252the parameter's type becomes a type that I summarize as being the array-decayed type.
     253The respective handlings of the following two parameter spellings shows that the array-spelled one is really, like the other, a pointer.
    236254\lstinput{12-16}{bkgd-carray-decay.c}
    237255As the @sizeof(x)@ meaning changed, compared with when run on a similarly-spelled local variable declaration,
    238 @gcc@ also gives this code the warning for the first assertion:
    239 \begin{cfa}
    240 warning: 'sizeof' on array function parameter 'x' will return size of 'float *'
    241 \end{cfa}
    242 The caller of such a function is left with the reality that a pointer parameter is a pointer, no matter how it is spelled:
     256GCC also gives this code the warning: ```sizeof' on array function parameter `x' will return size of `float *'.''
     257
     258The caller of such a function is left with the reality that a pointer parameter is a pointer, no matter how it's spelled:
    243259\lstinput{18-21}{bkgd-carray-decay.c}
    244260This fragment gives no warnings.
     
    256272depending on whether the object is a local variable or a parameter.
    257273
     274
    258275In summary, when a function is written with an array-typed parameter,
    259276\begin{itemize}
     
    266283As a result, a function with a pointer-to-array parameter sees the parameter exactly as the caller does:
    267284\lstinput{32-42}{bkgd-carray-decay.c}
    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.
    272 Includes interaction with \lstinline{const}ness, where ``immutable'' refers to a restriction on the callee's ability.}
    273 \label{bkgd:ar:usr:decay-parm}
     285
     286\VRef[Figure]{bkgd:ar:usr:decay-parm} gives the reference for the decay phenomenon seen in parameter decalarations.
     287
     288\begin{figure}
    274289\centering
    275290\begin{tabular}{llllll}
    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
     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
    304322\end{tabular}
    305 \end{table}
     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}
    306326
    307327
    308328\subsection{Lengths may vary, checking does not}
    309329
    310 When the desired number of elements is unknown at compile time, a variable-length array is a solution:
     330When the desired number of elements is unknown at compile time,
     331a variable-length array is a solution:
    311332\begin{cfa}
    312 int main( int argc, const char * argv[] ) {
     333int main( int argc, const char *argv[] ) {
    313334        assert( argc == 2 );
    314335        size_t n = atol( argv[1] );
    315         assert( 0 < n );
     336        assert( 0 < n && n < 1000 );
     337
    316338        float ar[n];
    317339        float b[10];
     340
    318341        // ... discussion continues here
    319342}
    320343\end{cfa}
    321 This 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@.
    322 The variable-sized allocation of @ar@ is provided by the @alloca@ routine, which bumps the stack pointer.
    323 Note, the C standard supports VLAs~\cite[\S~6.7.6.2.4]{C11} as a conditional feature, but the \CC standard does not;
    324 both @gcc@ and @g++@ support VLAs.
    325 As well, there is misinformation about VLAs, \eg VLAs cause stack failures or are inefficient.
    326 VLAs exist as far back as Algol W~\cite[\S~5.2]{AlgolW} and are a sound and efficient data type.
    327 
    328 For high-performance applications, the stack size can be fixed and small (coroutines or user-level threads).
    329 Here, VLAs can overflow the stack, so a heap allocation is used.
     344This arrangement allocates @n@ elements on the @main@ stack frame for @ar@, just as it puts 10 elements on the @main@ stack frame for @b@.
     345The variable-sized allocation of @ar@ is provided by @alloca@.
     346
     347In 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:
    330348\begin{cfa}
    331 float * ax1 = malloc( sizeof( float[n] ) );
    332 float * ax2 = malloc( n * sizeof( float ) );
    333 float * bx1 = malloc( sizeof( float[1000000] ) );
    334 float * bx2 = malloc( 1000000 * sizeof( float ) );
     349float *ax1 = malloc( sizeof( float[n] ) );
     350float *ax2 = malloc( n * sizeof( float ) );
     351float *bx1 = malloc( sizeof( float[1000000] ) );
     352float *bx2 = malloc( 1000000 * sizeof( float ) );
    335353\end{cfa}
    336354
     355
     356VLA
     357
    337358Parameter dependency
    338359
     
    342363
    343364
    344 \subsection{Dynamically sized, multidimensional arrays}
     365
     366\subsection{C has full-service, dynamically sized, multidimensional arrays (and \CC does not)}
    345367
    346368In C and \CC, ``multidimensional array'' means ``array of arrays.''  Other meanings are discussed in TODO.
     
    394416\section{Linked List}
    395417
    396 Linked-lists are blocks of storage connected using one or more pointers.
    397 The storage block is logically divided into data and links (pointers), where the links are the only component used by the list structure.
    398 Since the data is opaque, list structures are often polymorphic over the data, which is normally homogeneous.
    399 
    400418
    401419\section{String}
    402 
    403 A 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.
    404 A string can be read left-to-right, right-to-left, top-to-bottom, and have stacked elements (Arabic).
    405 
    406 An integer character constant is a sequence of one or more multibyte characters enclosed in single-quotes, as in @'x'@.
    407 A wide character constant is the same, except prefixed by the letter @L@, @u@, or @U@.
    408 With a few exceptions detailed later, the elements of the sequence are any members of the source character set;
    409 they are mapped in an implementation-defined manner to members of the execution character set.
    410 
    411 A C character-string literal is a sequence of zero or more multibyte characters enclosed in double-quotes, as in @"xyz"@.
    412 A UTF-8 string literal is the same, except prefixed by @u8@.
    413 A wide string literal is the same, except prefixed by the letter @L@, @u@, or @U@.
    414 
    415 For 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.
    416 For 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.
    417 For 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.
    418 The value of a string literal containing a multibyte character or escape sequence not represented in the executioncharacter set is implementation-defined.
    419 
    420 
    421 Another bad C design decision is to have null-terminated strings rather than maintaining a separate string length.
    422 \begin{quote}
    423 Technically, a string is an array whose elements are single characters.
    424 The compiler automatically places the null character @\0@ at the end of each such string, so programs can conveniently find the end.
    425 This 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

    rdc58e5d raf746cc  
    5757        f( &ar );
    5858
    59         float fs[] = {3.14, 1.77};
     59        float fs[] = {3.14, 1.707};
    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) );
    6864}
    6965
  • doc/theses/mike_brooks_MMath/programs/bkgd-carray-decay.c

    rdc58e5d raf746cc  
    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{// parameter is pointer}$
     24        char *cp = "hello";                     $\C{// pointer to read-only data [decay here]}$
     25        void edit( char c[] ) {         $\C{// param is pointer}$
    2626                c[3] = 'p';
    2727        }
    2828        edit( ca );                                     $\C{// ok [decay here]}$
    29         edit( cp );                                     $\C{// Segmentation fault}$
     29        edit( c p );                            $\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

    rdc58e5d raf746cc  
    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 
    419418        cltr->sched.caches = alloc( target, cltr->sched.caches`realloc );
    420419
     
    429428
    430429        // Make sure that everything is consistent
    431 //      /* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) );
     430        /* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) );
    432431        /* paranoid */ check_readyQ( cltr );
    433432
  • libcfa/src/concurrency/kernel/startup.cfa

    rdc58e5d raf746cc  
    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

    rdc58e5d raf746cc  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Apr  7 21:54:29 2024
    13 // Update Count     : 1644
     12// Last Modified On : Wed Jan  3 21:30:54 2024
     13// Update Count     : 1619
    1414//
    1515
     
    114114
    115115
    116 // CFA generic Bsearchl does not inline, so substitute with hand-coded binary-search.
     116// 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_0_calls;
     192                unsigned int free_calls, free_null_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 {                                             // 4-byte word => 8-byte header, 8-byte word => 16-byte header
     234                                struct RealHeader {
    235235                                        union {
    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
     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                                                };
    241246                                        };
    242                                         size_t size;                                            // allocation size in bytes
    243247                                } real; // RealHeader
    244248
     
    257261
    258262        struct CALIGN FreeHeader {
     263                size_t blockSize CALIGN;                                                // size of allocations on this list
    259264                #ifdef OWNERSHIP
    260265                #ifdef RETURNSPIN
     
    266271                Storage * freeList;                                                             // thread free list
    267272                Heap * homeManager;                                                             // heap owner (free storage to bucket, from bucket to heap)
    268                 size_t blockSize;                                                               // size of allocations on this list
    269273        }; // FreeHeader
    270274
     
    365369static __thread size_t PAD1 CALIGN TLSMODEL __attribute__(( unused )); // protect false sharing
    366370static __thread Heap * heapManager CALIGN TLSMODEL;
    367 static __thread bool heapManagerBootFlag CALIGN TLSMODEL = false;
     371static  __thread bool heapManagerBootFlag CALIGN TLSMODEL = false;
    368372static __thread size_t PAD2 CALIGN TLSMODEL __attribute__(( unused )); // protect further false sharing
    369373
     
    591595
    592596#ifdef __STATISTICS__
     597static HeapStatistics stats;                                                    // zero filled
     598
    593599#define prtFmt \
    594600        "\nHeap statistics: (storage request / allocation)\n" \
     
    601607        "  resize    >0 calls %'u; 0 calls %'u; storage %'llu / %'llu bytes\n" \
    602608        "  realloc   >0 calls %'u; 0 calls %'u; storage %'llu / %'llu bytes\n" \
    603         "  free      !null calls %'u; null/0 calls %'u; storage %'llu / %'llu bytes\n" \
     609        "  free      !null calls %'u; null calls %'u; storage %'llu / %'llu bytes\n" \
    604610        "  return    pulls %'u; pushes %'u; storage %'llu / %'llu bytes\n" \
    605611        "  sbrk      calls %'u; storage %'llu bytes\n" \
     
    621627                        resize_calls, resize_0_calls, resize_storage_request, resize_storage_alloc,
    622628                        realloc_calls, realloc_0_calls, realloc_storage_request, realloc_storage_alloc,
    623                         free_calls, free_null_0_calls, free_storage_request, free_storage_alloc,
     629                        free_calls, free_null_calls, free_storage_request, free_storage_alloc,
    624630                        return_pulls, return_pushes, return_storage_request, return_storage_alloc,
    625631                        sbrk_calls, sbrk_storage,
     
    644650        "<total type=\"resize\" >0 count=\"%'u;\" 0 count=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
    645651        "<total type=\"realloc\" >0 count=\"%'u;\" 0 count=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
    646         "<total type=\"free\" !null=\"%'u;\" 0 null/0=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
     652        "<total type=\"free\" !null=\"%'u;\" 0 null=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
    647653        "<total type=\"return\" pulls=\"%'u;\" 0 pushes=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
    648654        "<total type=\"sbrk\" count=\"%'u;\" size=\"%'llu\"/> bytes\n" \
     
    664670                        resize_calls, resize_0_calls, resize_storage_request, resize_storage_alloc,
    665671                        realloc_calls, realloc_0_calls, realloc_storage_request, realloc_storage_alloc,
    666                         free_calls, free_null_0_calls, free_storage_request, free_storage_alloc,
     672                        free_calls, free_null_calls, free_storage_request, free_storage_alloc,
    667673                        return_pulls, return_pushes, return_storage_request, return_storage_alloc,
    668674                        sbrk_calls, sbrk_storage,
     
    793799        } else {
    794800                fakeHeader( header, alignment );
    795                 if ( unlikely( MmappedBit( header ) ) ) {               // mmapped storage ?
     801                if ( unlikely( MmappedBit( header ) ) ) {               // mmapped ?
    796802                        verify( addr < heapBegin || heapEnd < addr );
    797803                        size = ClearStickyBits( header->kind.real.blockSize ); // mmap size
    798                         freeHead = 0p;                                                          // prevent uninitialized warning
    799804                        return true;
    800805                } // if
     
    899904
    900905
     906#define BOOT_HEAP_MANAGER \
     907        if ( unlikely( ! heapMasterBootFlag ) ) { \
     908                heapManagerCtor(); /* trigger for first heap */ \
     909        } /* if */
     910
    901911#ifdef __STATISTICS__
    902912#define STAT_NAME __counter
    903913#define STAT_PARM , unsigned int STAT_NAME
    904914#define STAT_ARG( name ) , name
    905 #define STAT_0_CNT( counter ) heapManager->stats.counters[counter].calls_0 += 1
     915#define STAT_0_CNT( counter ) stats.counters[counter].calls_0 += 1
    906916#else
    907917#define STAT_NAME
     
    911921#endif // __STATISTICS__
    912922
    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// 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 */
     927#else
     928#define __NULL_0_ALLOC__
     929#endif // __NONNULL_0_ALLOC__
     930
     931#define PROLOG( counter, ... ) \
     932        BOOT_HEAP_MANAGER; \
     933        if ( \
     934                __NULL_0_ALLOC__ \
     935                unlikely( size > ULONG_MAX - sizeof(Heap.Storage) ) ) { /* error check */ \
    923936                STAT_0_CNT( counter ); \
    924                 __VA_ARGS__; /* call routine, if specified */ \
     937                __VA_ARGS__; \
    925938                return 0p; \
    926939        } /* if */
    927 #else
    928 #define __NULL_0_ALLOC__( counter, ... )
    929 #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__
    940 
    941 #define PROLOG( counter, ... ) \
    942         BOOT_HEAP_MANAGER; \
    943         __NULL_0_ALLOC__( counter, __VA_ARGS__ ) \
    944         __OVERFLOW_MALLOC__( __VA_ARGS__ )
     940
    945941
    946942#define SCRUB_SIZE 1024lu
     
    952948        PROLOG( STAT_NAME );
    953949
     950        verify( heapManager );
    954951        Heap.Storage * block;                                                           // pointer to new block of storage
    955952
     
    959956
    960957        #ifdef __STATISTICS__
    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;
     958        stats.counters[STAT_NAME].calls += 1;
    967959        stats.counters[STAT_NAME].request += size;
    968960        #endif // __STATISTICS__
     
    10861078
    10871079static 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 
    10921080        verify( addr );
    10931081
     
    11031091        #endif // __STATISTICS__ || __CFA_DEBUG__
    11041092
    1105         // Do not move these down because heap can be null!
    11061093        #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
    11131094        stats.free_storage_request += rsize;
    11141095        stats.free_storage_alloc += size;
     
    11361117                } // if
    11371118        } else {
    1138                 assert( freeHead );
    11391119                #ifdef __CFA_DEBUG__
    11401120                // memset is NOT always inlined!
     
    13411321        // call to malloc(), alloc(), calloc() or realloc(). If the area pointed to was moved, a free(oaddr) is done.
    13421322        void * resize( void * oaddr, size_t size ) libcfa_public {
    1343           if ( unlikely( oaddr == 0p ) ) {                                      // => malloc( size )
     1323          if ( unlikely( oaddr == 0p ) ) {                              // => malloc( size )
    13441324                        return doMalloc( size STAT_ARG( RESIZE ) );
    13451325                } // if
     
    13531333
    13541334                size_t odsize = DataStorage( bsize, oaddr, header ); // data storage available in bucket
    1355                 // same size, DO NOT PRESERVE STICKY PROPERTIES.
     1335                // same size, DO NOT preserve STICKY PROPERTIES.
    13561336                if ( oalign == libAlign() && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
    13571337                        ClearZeroFillBit( header );                                     // no alignment and turn off 0 fill
     
    13661346                } // if
    13671347
    1368                 // change size, DO NOT PRESERVE STICKY PROPERTIES.
     1348                // change size, DO NOT preserve STICKY PROPERTIES.
    13691349                doFree( oaddr );                                                                // free previous storage
    13701350
     
    13761356        // the old and new sizes.
    13771357        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 );
    13811358          if ( unlikely( oaddr == 0p ) ) {                                      // => malloc( size )
    13821359                  return doMalloc( size STAT_ARG( REALLOC ) );
     
    15211498                } // if
    15221499
     1500                #ifdef __STATISTICS__
     1501                incCalls( FREE );
     1502                #endif // __STATISTICS__
     1503
    15231504                doFree( addr );                                                                 // handles heapManager == nullptr
    15241505        } // free
     
    15981579                #endif // __STATISTICS__
    15991580        } // malloc_stats_clear
     1581
    16001582
    16011583        // Changes the file descriptor where malloc_stats() writes statistics.
     
    17181700        } // if
    17191701
    1720         // change size, DO NOT PRESERVE STICKY PROPERTIES.
     1702        // change size, DO NOT preserve STICKY PROPERTIES.
    17211703        doFree( oaddr );                                                                        // free previous storage
    17221704        return memalignNoStats( nalign, size STAT_ARG( RESIZE ) ); // create new aligned area
     
    17251707
    17261708void * 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 );
    17301709  if ( unlikely( oaddr == 0p ) ) {                                              // => malloc( size )
    17311710                return memalignNoStats( nalign, size STAT_ARG( REALLOC ) );
  • libcfa/src/heap.hfa

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

    rdc58e5d raf746cc  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Apr 12 07:39:15 2024
    13 // Update Count     : 812
     12// Last Modified On : Sun Mar 17 08:25:31 2024
     13// Update Count     : 796
    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 
    161 extern "C" ssize_t write(int fd, const void *buf, size_t count);
     158static inline T_align   ?`align   ( size_t a )  { return (T_align){a}; }
     159static inline T_resize  ?`resize  ( void * a )  { return (T_resize){a}; }
     160
    162161static inline forall( T & | sized(T) ) {
    163162        S_fill(T) ?`fill ( T t ) {
     
    170169                return ret;
    171170        }
    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}; }
     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}; }
    178177
    179178        T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill ) {
     
    183182
    184183                if ( Resize ) {
    185                         ptr = (T*)(void *)resize( (void *)Resize, Align, Dim * size );
     184                        ptr = (T*) (void *) resize( (void *)Resize, Align, Dim * size );
    186185                } else if ( Realloc ) {
    187186                        if ( Fill.tag != '0' ) copy_end = min(malloc_size( Realloc ), Dim * size );
    188                         ptr = (T *)(void *)realloc( (void *)Realloc, Align, Dim * size );
     187                        ptr = (T *) (void *) realloc( (void *)Realloc, Align, Dim * size );
    189188                } else {
    190                         ptr = (T *)(void *) memalign( Align, Dim * size );
     189                        ptr = (T *) (void *) memalign( Align, Dim * size );
    191190                }
    192191
  • src/AST/Pass.hpp

    rdc58e5d raf746cc  
    252252private:
    253253
    254         /// The return type of the general call_accept function.
     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.
    255259        template< typename node_t >
    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
     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                        >
    259268                >;
    260269
    261270        template< typename node_t >
    262         auto call_accept( const node_t * node ) -> call_accept_result_t<node_t>;
     271        auto call_accept( const node_t * node )
     272                -> typename generic_call_accept_result<node_t>::type;
    263273
    264274        // requests WithStmtsToAdd directly add to this statement, as if it is a compound.
  • src/AST/Pass.impl.hpp

    rdc58e5d raf746cc  
    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        }
    111123}
    112124
     
    114126template< typename node_t >
    115127auto ast::Pass< core_t >::call_accept( const node_t * node ) ->
    116                 ast::Pass< core_t >::call_accept_result_t<node_t> {
     128        typename ast::Pass< core_t >::template generic_call_accept_result<node_t>::type
     129{
    117130        __pedantic_pass_assert( __visit_children() );
    118131        __pedantic_pass_assert( node );
    119132
     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
    120136        auto nval = node->accept( *this );
    121         return { nval != node, nval };
     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
     145template< typename core_t >
     146ast::__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
     154template< typename core_t >
     155ast::__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 };
    122161}
    123162
     
    191230ast::__pass::template resultNstmt<container_t> ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
    192231        __pedantic_pass_assert( __visit_children() );
    193         __pedantic_pass_assert( !statements.empty() );
     232        if ( statements.empty() ) return {};
    194233
    195234        // We are going to aggregate errors for all these statements
     
    224263                        const ast::Stmt * new_stmt = stmt->accept( *this );
    225264                        assert( new_stmt );
     265                        if ( new_stmt != stmt ) { new_kids.differs = true; }
    226266
    227267                        // Make sure that it is either adding statements or declartions but not both
     
    236276                        // Now add the statement if there is one
    237277                        if ( new_stmt != stmt ) {
    238                                 new_kids.differs = true;
    239                                 new_kids.values.emplace_back( new_stmt );
     278                                new_kids.values.emplace_back( new_stmt, i, false );
    240279                        } else {
    241                                 new_kids.values.emplace_back( i );
     280                                new_kids.values.emplace_back( nullptr, i, true );
    242281                        }
    243282
     
    259298ast::__pass::template resultN<container_t, node_t> ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
    260299        __pedantic_pass_assert( __visit_children() );
    261         __pedantic_pass_assert( !container.empty() );
    262 
    263         // Collect errors from processing all these nodes.
     300        if ( container.empty() ) return {};
    264301        SemanticErrorException errors;
    265302
     
    305342        static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
    306343
    307         auto result = call_accept( old_val );
    308         if ( result.differs ) {
     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 ) {
    309349                auto new_parent = __pass::mutate<core_t>(parent);
    310                 result.apply( new_parent, field );
     350                new_val.apply(new_parent, field);
    311351                parent = new_parent;
    312352        }
     
    326366        static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
    327367
    328         auto result = call_accept_top( old_val );
    329         if ( result.differs ) {
     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 ) {
    330373                auto new_parent = __pass::mutate<core_t>(parent);
    331                 result.apply( new_parent, field );
     374                new_val.apply(new_parent, field);
    332375                parent = new_parent;
    333376        }
     
    347390        static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
    348391
    349         auto result = call_accept_as_compound( old_val );
    350         if ( result.differs ) {
     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 ) {
    351397                auto new_parent = __pass::mutate<core_t>(parent);
    352                 result.apply( new_parent, child );
     398                new_val.apply( new_parent, child );
    353399                parent = new_parent;
    354400        }
     
    406452template< typename core_t >
    407453inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) {
    408         if ( auto ptr = __pass::translationUnit( visitor.core, 0 ) ) {
     454        if ( auto ptr = __pass::translation_unit::get_cptr( visitor.core, 0 ) ) {
    409455                ValueGuard<const TranslationUnit *> guard( *ptr );
    410456                *ptr = &unit;
  • src/AST/Pass.proto.hpp

    rdc58e5d raf746cc  
    154154                bool is_old;
    155155
    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) {}
     156                delta(const Stmt * s, ssize_t i, bool old) :
     157                        new_val(s), old_idx(i), is_old(old) {}
    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() );
     190                                return delta( stmt.release(), -1, false );
    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 ) );
     203                                return delta( new DeclStmt( d->location, d ), -1, false );
    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
     234template<bool is_void>
     235struct __assign;
     236
     237template<>
     238struct __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
     245template<>
     246struct __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
     257template<bool is_void>
     258struct __return;
     259
     260template<>
     261struct __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
     269template<>
     270struct __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 );
    228274        }
    229275};
     
    251297        );
    252298
    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         }
     299        __assign<
     300                std::is_void<
     301                        decltype( core.previsit( node ) )
     302                >::value
     303        >::result( core, node );
    261304}
    262305
     
    269312        decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
    270313{
    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         }
     314        return __return<
     315                std::is_void<
     316                        decltype( core.postvisit( node ) )
     317                >::value
     318        >::result( core, node );
    279319}
    280320
     
    310350FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
    311351FIELD_PTR( visitor, ast::Pass<core_t> * const )
    312 FIELD_PTR( translationUnit, const TranslationUnit * )
    313352
    314353// Remove the macro to make sure we don't clash
     
    507546} // namespace forall
    508547
     548// For passes that need access to the global context. Searches `translationUnit`
     549namespace 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
    509562// For passes, usually utility passes, that have a result.
    510563namespace result {
  • src/Parser/StatementNode.cc

    rdc58e5d raf746cc  
    122122        ast::Expr * cond = nullptr;
    123123        if ( ctl->condition ) {
    124                 cond = maybeMoveBuild( ctl->condition );
     124                // compare the provided condition against 0
     125                cond = notZeroExpr( maybeMoveBuild( ctl->condition ) );
    125126        } else {
    126127                for ( ast::ptr<ast::Stmt> & stmt : inits ) {
     
    128129                        auto declStmt = stmt.strict_as<ast::DeclStmt>();
    129130                        auto dwt = declStmt->decl.strict_as<ast::DeclWithType>();
    130                         ast::Expr * nze = new ast::VariableExpr( dwt->location, dwt );
     131                        ast::Expr * nze = notZeroExpr( new ast::VariableExpr( dwt->location, dwt ) );
    131132                        cond = cond ? new ast::LogicalExpr( dwt->location, cond, nze, ast::AndExpr ) : nze;
    132133                }
     
    199200        // do-while cannot have declarations in the contitional, so init is always empty
    200201        return new ast::WhileDoStmt( location,
    201                 maybeMoveBuild( ctl ),
     202                notZeroExpr( maybeMoveBuild( ctl ) ),
    202203                buildMoveSingle( stmt ),
    203204                buildMoveOptional( else_ ),
     
    212213
    213214        ast::Expr * astcond = nullptr;                                          // maybe empty
    214         astcond = maybeMoveBuild( forctl->condition );
     215        astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) );
    215216
    216217        ast::Expr * astincr = nullptr;                                          // maybe empty
     
    329330        clause->target = maybeBuild( targetExpr );
    330331        clause->stmt = maybeMoveBuild( stmt );
    331         clause->when_cond = maybeMoveBuild( when );
     332        clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
    332333
    333334        ExpressionNode * next = targetExpr->next;
     
    344345ast::WaitForStmt * build_waitfor_else( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt ) {
    345346        existing->else_stmt = maybeMoveBuild( stmt );
    346         existing->else_cond = maybeMoveBuild( when );
     347        existing->else_cond = notZeroExpr( maybeMoveBuild( when ) );
    347348
    348349        (void)location;
     
    353354        existing->timeout_time = maybeMoveBuild( timeout );
    354355        existing->timeout_stmt = maybeMoveBuild( stmt );
    355         existing->timeout_cond = maybeMoveBuild( when );
     356        existing->timeout_cond = notZeroExpr( maybeMoveBuild( when ) );
    356357
    357358        (void)location;
     
    361362ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
    362363        ast::WhenClause * clause = new ast::WhenClause( loc );
    363         clause->when_cond = maybeMoveBuild( when );
     364        clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
    364365        clause->stmt = maybeMoveBuild( stmt );
    365366        clause->target = maybeMoveBuild( targetExpr );
     
    368369ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation & loc, ExpressionNode * when, StatementNode * stmt ) {
    369370        ast::WhenClause * clause = new ast::WhenClause( loc );
    370         clause->when_cond = maybeMoveBuild( when );
     371        clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
    371372        clause->stmt = maybeMoveBuild( stmt );
    372373        return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause );
     
    507508
    508509        ast::Expr * astcond = nullptr;                                          // maybe empty
    509         astcond = maybeMoveBuild( forctl->condition );
     510        astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) );
    510511
    511512        ast::Expr * astincr = nullptr;                                          // maybe empty
  • src/Parser/module.mk

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

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

    rdc58e5d raf746cc  
    4646#include "AST/Type.hpp"
    4747#include "Common/utility.h"       // for move, copy
     48#include "Parser/parserutility.h" // for notZeroExpr
    4849#include "SymTab/Mangler.h"
    4950#include "Tuples/Tuples.h"        // for handleTupleAssignment
     
    15131514        void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) {
    15141515                CandidateFinder finder1( context, tenv );
    1515                 ast::ptr<ast::Expr> arg1 = createCondExpr( logicalExpr->arg1 );
     1516                ast::ptr<ast::Expr> arg1 = notZeroExpr( logicalExpr->arg1 );
    15161517                finder1.find( arg1, ResolveMode::withAdjustment() );
    15171518                if ( finder1.candidates.empty() ) return;
    15181519
    15191520                CandidateFinder finder2( context, tenv );
    1520                 ast::ptr<ast::Expr> arg2 = createCondExpr( logicalExpr->arg2 );
     1521                ast::ptr<ast::Expr> arg2 = notZeroExpr( logicalExpr->arg2 );
    15211522                finder2.find( arg2, ResolveMode::withAdjustment() );
    15221523                if ( finder2.candidates.empty() ) return;
     
    15441545        void Finder::postvisit( const ast::ConditionalExpr * conditionalExpr ) {
    15451546                // candidates for condition
    1546                 ast::ptr<ast::Expr> arg1 = createCondExpr( conditionalExpr->arg1 );
     1547                ast::ptr<ast::Expr> arg1 = notZeroExpr( conditionalExpr->arg1 );
    15471548                CandidateFinder finder1( context, tenv );
    15481549                finder1.find( arg1, ResolveMode::withAdjustment() );
     
    21652166                CandidateRef & choice = winners.front();
    21662167                return choice->expr;
    2167 }
    2168 
    2169 const 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         );
     2168                // return std::move( choice->expr.get() );
    21832169}
    21842170
  • src/ResolvExpr/CandidateFinder.hpp

    rdc58e5d raf746cc  
    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.
    75 const ast::Expr * createCondExpr( const ast::Expr * expr );
    7674
    7775} // namespace ResolvExpr
  • src/ResolvExpr/Resolver.cc

    rdc58e5d raf746cc  
    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 
    350342        /// check if a type is a character type
    351343        bool isCharType( const ast::Type * t ) {
     
    364356                return it != end;
    365357        }
    366 } // anonymous namespace
     358}
    367359
    368360class Resolver final
     
    737729const ast::IfStmt * Resolver::previsit( const ast::IfStmt * ifStmt ) {
    738730        return ast::mutate_field(
    739                 ifStmt, &ast::IfStmt::cond, findCondExpression( ifStmt->cond, context ) );
     731                ifStmt, &ast::IfStmt::cond, findIntegralExpression( ifStmt->cond, context ) );
    740732}
    741733
    742734const ast::WhileDoStmt * Resolver::previsit( const ast::WhileDoStmt * whileDoStmt ) {
    743735        return ast::mutate_field(
    744                 whileDoStmt, &ast::WhileDoStmt::cond, findCondExpression( whileDoStmt->cond, context ) );
     736                whileDoStmt, &ast::WhileDoStmt::cond, findIntegralExpression( whileDoStmt->cond, context ) );
    745737}
    746738
     
    748740        if ( forStmt->cond ) {
    749741                forStmt = ast::mutate_field(
    750                         forStmt, &ast::ForStmt::cond, findCondExpression( forStmt->cond, context ) );
     742                        forStmt, &ast::ForStmt::cond, findIntegralExpression( forStmt->cond, context ) );
    751743        }
    752744
     
    10831075
    10841076                // Resolve the conditions as if it were an IfStmt, statements normally
    1085                 clause2->when_cond = findCondExpression( clause.when_cond, context );
     1077                clause2->when_cond = findSingleExpression( clause.when_cond, context );
    10861078                clause2->stmt = clause.stmt->accept( *visitor );
    10871079
     
    10971089                        new ast::BasicType{ ast::BasicType::LongLongUnsignedInt };
    10981090                auto timeout_time = findSingleExpression( stmt->timeout_time, target, context );
    1099                 auto timeout_cond = findCondExpression( stmt->timeout_cond, context );
     1091                auto timeout_cond = findSingleExpression( stmt->timeout_cond, context );
    11001092                auto timeout_stmt = stmt->timeout_stmt->accept( *visitor );
    11011093
     
    11101102        if ( stmt->else_stmt ) {
    11111103                // resolve the condition like IfStmt, stmts normally
    1112                 auto else_cond = findCondExpression( stmt->else_cond, context );
     1104                auto else_cond = findSingleExpression( stmt->else_cond, context );
    11131105                auto else_stmt = stmt->else_stmt->accept( *visitor );
    11141106
  • src/Validate/ImplementEnumFunc.cpp

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