Changeset 1f44196
- Timestamp:
- Nov 29, 2016, 3:30:59 PM (6 years ago)
- Branches:
- aaron-thesis, arm-eh, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
- Children:
- 8e5724e
- Parents:
- 3a2128f (diff), 9129a84 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 22 added
- 5 deleted
- 70 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/proposals/concurrency/Makefile
r3a2128f r1f44196 9 9 SOURCES = ${addsuffix .tex, \ 10 10 concurrency \ 11 style \ 12 glossary \ 11 13 } 12 14 -
doc/proposals/concurrency/concurrency.tex
r3a2128f r1f44196 14 14 15 15 % Latex packages used in the document. 16 \usepackage[T1]{fontenc} 16 \usepackage[T1]{fontenc} % allow Latin1 (extended ASCII) characters 17 17 \usepackage{textcomp} 18 18 \usepackage[latin1]{inputenc} 19 19 \usepackage{fullpage,times,comment} 20 20 \usepackage{epic,eepic} 21 \usepackage{upquote} 21 \usepackage{upquote} % switch curled `'" to straight 22 22 \usepackage{calc} 23 23 \usepackage{xspace} … … 25 25 \usepackage{tabularx} 26 26 \usepackage[acronym]{glossaries} 27 \usepackage{varioref} 27 \usepackage{varioref} % extended references 28 28 \usepackage{inconsolata} 29 \usepackage{listings} 30 \usepackage[flushmargin]{footmisc} 31 \usepackage{latexsym} 32 \usepackage{mathptmx} 29 \usepackage{listings} % format program code 30 \usepackage[flushmargin]{footmisc} % support label/reference in footnote 31 \usepackage{latexsym} % \Box glyph 32 \usepackage{mathptmx} % better math font with "times" 33 33 \usepackage[usenames]{color} 34 34 \usepackage[pagewise]{lineno} 35 35 \usepackage{fancyhdr} 36 36 \renewcommand{\linenumberfont}{\scriptsize\sffamily} 37 \input{ common}% bespoke macros used in the document37 \input{style} % bespoke macros used in the document 38 38 \usepackage[dvips,plainpages=false,pdfpagelabels,pdfpagemode=UseNone,colorlinks=true,pagebackref=true,linkcolor=blue,citecolor=blue,urlcolor=blue,pagebackref=true,breaklinks=true]{hyperref} 39 39 \usepackage{breakurl} … … 44 44 \renewcommand{\UrlFont}{\small\sf} 45 45 46 \setlength{\topmargin}{-0.45in} 46 \setlength{\topmargin}{-0.45in} % move running title into header 47 47 \setlength{\headsep}{0.25in} 48 48 … … 86 86 \title{Concurrency in \CFA} 87 87 \author{Thierry Delisle \\ 88 Dept.of Computer Science, University of Waterloo, \\ Waterloo, Ontario, Canada88 School of Computer Science, University of Waterloo, \\ Waterloo, Ontario, Canada 89 89 } 90 90 … … 100 100 101 101 \section{Introduction} 102 This proposal provides a minimal core concurrency API that is both simple, efficient and can be reused to build higher-level features. The simplest possible core is a thread and a lock but this low-level approach is hard to master. An easier approach for users is to support higher-level construct as the basis of the concurrency in \CFA. 103 Indeed, for highly productive parallel programming high-level approaches are much more popular\cite{HPP:Study}. Examples are task based parallelism, message passing, implicit threading. 104 105 There are actually two problems that need to be solved in the design of the concurrency for a language. Which concurrency tools are available to the users and which parallelism tools are available. While these two concepts are often seen together, they are in fact distinct concepts that require different sorts of tools\cite{Buhr05a}. Concurrency tools need to handle mutual exclusion and synchronization while parallelism tools are more about performance, cost and resource utilization. 102 This proposal provides a minimal core concurrency API that is both simple, efficient and can be reused to build higher-level features. The simplest possible concurrency core is a thread and a lock but this low-level approach is hard to master. An easier approach for users is to support higher-level constructs as the basis of the concurrency in \CFA. Indeed, for highly productive parallel programming, high-level approaches are much more popular~\cite{HPP:Study}. Examples are task based, message passing and implicit threading. 103 104 There are actually two problems that need to be solved in the design of the concurrency for a programming language: which concurrency tools are available to the users and which parallelism tools are available. While these two concepts are often seen together, they are in fact distinct concepts that require different sorts of tools~\cite{Buhr05a}. Concurrency tools need to handle mutual exclusion and synchronization, while parallelism tools are more about performance, cost and resource utilization. 106 105 107 106 % ##### ####### # # ##### # # ###### ###### ####### # # ##### # # … … 114 113 115 114 \section{Concurrency} 116 % Several tool can be used to solve concurrency challenges. Since these challenges always appear with the use of mutable shared state, some languages and libraries simply disallow mutable shared-state (Erlang\cite{Erlang}, Haskell\cite{Haskell}, Akka (Scala)\cite{Akka}). In these paradigms, interaction among concurrent objects rely on message passing or other paradigms that often closely relate to networking concepts. However, in imperative or OO languages, these approaches entail a clear distinction between concurrent and non-concurrent paradigms (i.e. message passing versus routine call). Which in turns mean that programmers need to learn two sets of designs patterns in order to be effective. Approaches based on shared memory are more closely related to non-concurrent paradigms since they often rely on non-concurrent constructs like routine calls and objects. At a lower level these can be implemented as locks and atomic operations. However, for productivity reasons it is desireable to have a higher-level construct to be the core concurrency paradigm\cite{HPP:Study}. This project proposes Monitors\cite{Hoare74} as the core concurrency construct. 117 % \\ 118 119 Several tool can be used to solve concurrency challenges. Since these challenges always appear with the use of mutable shared state, some languages and libraries simply disallow mutable shared-state (Erlang\cite{Erlang}, Haskell\cite{Haskell}, Akka (Scala)\cite{Akka}). In these paradigms, interaction among concurrent objects rely on message passing\cite{Thoth,Harmony,V-Kernel} or other paradigms that often closely relate to networking concepts. However, in imperative or OO languages, these approaches entail a clear distinction between concurrent and non-concurrent paradigms (i.e. message passing versus routine call). Which in turns mean that programmers need to learn two sets of designs patterns in order to be effective. Approaches based on shared memory are more closely related to non-concurrent paradigms since they often rely on non-concurrent constructs like routine calls and objects. At a lower level these can be implemented as locks and atomic operations. Many such mechanisms have been proposed, including semaphores~\cite{Dijkstra68b} and path expressions~\cite{Campbell74}. However, for productivity reasons it is desireable to have a higher-level construct to be the core concurrency paradigm\cite{HPP:Study}. One of the most natural, elegant, and efficient mechanisms for synchronization and communication, especially for shared memory systems, is the \emph{monitor}. 120 121 Monitors were first proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}. 122 Many programming languages---e.g., Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java}---provide monitors as explicit language constructs. In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as semaphores or locks to simulate monitors. For these reasons, this project proposes Monitors as the core concurrency construct. 123 \\ 124 125 Finally, an approach that is worth mentionning because it is gaining in popularity is transactionnal memory\cite{Dice10}. However, the performance and feature set is currently too restrictive to be possible to add such a paradigm to a language like C or \CC\cit, which is why it was rejected as the core paradigm for concurrency in \CFA. 115 Several tool can be used to solve concurrency challenges. Since these challenges always appear with the use of mutable shared-state, some languages and libraries simply disallow mutable shared-state (Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, Akka (Scala)~\cite{Akka}). In these paradigms, interaction among concurrent objects relies on message passing~\cite{Thoth,Harmony,V-Kernel} or other paradigms that closely relate to networking concepts (channels\cit for example). However, in languages that use routine calls as their core abstraction mechanism, these approaches force a clear distinction between concurrent and non-concurrent paradigms (i.e., message passing versus routine call). Which in turn means that, in order to be effective, programmers need to learn two sets of designs patterns. This distinction can be hidden away in library code, but effective use of the librairy still has to take both paradigms into account. Approaches based on shared memory are more closely related to non-concurrent paradigms since they often rely on basic constructs like routine calls and objects. At a lower level these can be implemented as locks and atomic operations. Many such mechanisms have been proposed, including semaphores~\cite{Dijkstra68b} and path expressions~\cite{Campbell74}. However, for productivity reasons it is desireable to have a higher-level construct be the core concurrency paradigm~\cite{HPP:Study}. An approach that is worth mentionning because it is gaining in popularity is transactionnal memory~\cite{Dice10}[Check citation]. While this approach is even pursued by system languages like \CC\cit, the performance and feature set is currently too restrictive to add such a paradigm to a language like C or \CC\cit, which is why it was rejected as the core paradigm for concurrency in \CFA. One of the most natural, elegant, and efficient mechanisms for synchronization and communication, especially for shared memory systems, is the \emph{monitor}. Monitors were first proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}. Many programming languages---e.g., Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java}---provide monitors as explicit language constructs. In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as semaphores or locks to simulate monitors. For these reasons, this project proposes monitors as the core concurrency construct. 126 116 127 117 % # # ####### # # ### ####### ####### ###### ##### … … 134 124 135 125 \subsection{Monitors} 136 A monitor is a set of routines that ensure mutual exclusion when accessing shared state. This concept is generally associated with Object-Oriented Languages like Java \cite{Java} or \uC\cite{uC++book} but does not strictly require OOP semantics. The only requirements is the ability to declare a handle to a shared object and a set of routines that act on it :126 A monitor is a set of routines that ensure mutual exclusion when accessing shared state. This concept is generally associated with Object-Oriented Languages like Java~\cite{Java} or \uC~\cite{uC++book} but does not strictly require OOP semantics. The only requirements is the ability to declare a handle to a shared object and a set of routines that act on it : 137 127 \begin{lstlisting} 138 128 typedef /*some monitor type*/ monitor; … … 154 144 155 145 \subsubsection{Call semantics} \label{call} 156 The above example of monitors already displays some of their intrinsic caracteristics. Indeed, it is necessary to use pass-by-reference over pass-by-value for monitor routines. This semantics is important because at their core, monitors are implicit mutual exclusion objects (locks), and these objects cannot be copied. Therefore, monitors are implicitly non-copyable. 157 \\ 158 159 Another aspect to consider is when a monitor acquires its mutual exclusion. Indeed, a monitor may need to be passed through multiple helper routines that do not acquire the monitor mutual exclusion on entry. Examples of this can be both generic helper routines (\code{swap}, \code{sort}, etc.) or specific helper routines like the following example : 160 161 \begin{lstlisting} 162 mutex struct counter_t { /*...*/ }; 163 164 void ?{}(counter_t & nomutex this); 165 int ++?(counter_t & mutex this); 166 void ?{}(Int * this, counter_t & mutex cnt); 167 \end{lstlisting} 168 *semantics of the declaration of \code{mutex struct counter_t} are discussed in details in section \ref{data} 169 \\ 170 171 This example is of a monitor implementing an atomic counter. Here, the constructor uses the \code{nomutex} keyword to signify that it does not acquire the coroutine mutual exclusion when constructing. This is because object not yet constructed should never be shared and therefore do not require mutual exclusion. The prefix increment operator 172 uses \code{mutex} to protect the incrementing process from race conditions. Finally, we have a conversion operator from \code{counter_t} to \code{Int}. This conversion may or may not require the \code{mutex} key word depending whether or not reading an \code{Int} is an atomic operation or not. 173 \\ 174 175 Having both \code{mutex} and \code{nomutex} keywords could be argued to be redundant based on the meaning of a routine having neither of these keywords. If there were a meaning to routine \code{void foo(counter_t & this)} then one could argue that it should be to default to the safest option : \code{mutex}. On the other hand, the option of having routine \code{void foo(counter_t & this)} mean \code{nomutex} is unsafe by default and may easily cause subtle errors. It can be argued that this is the more "normal" behavior, \code{nomutex} effectively stating explicitly that "this routine has nothing special". An other alternative is to make one of these keywords mandatory, which would provide the same semantics but without the ambiguity of supporting routine \code{void foo(counter_t & this)}. Mandatory keywords would also have the added benefice of being more clearly self-documented but at the cost of extra typing. In the end, which solution should be picked is still up for debate. For the reminder of this proposal, the explicit approach will be used for the sake of clarity. 176 \\ 177 178 Regardless of which keyword is kept, it is important to establish when mutex/nomutex may be used depending on type parameters. 146 The above monitor example displays some of the intrinsic characteristics. Indeed, it is necessary to use pass-by-reference over pass-by-value for monitor routines. This semantics is important because at their core, monitors are implicit mutual-exclusion objects (locks), and these objects cannot be copied. Therefore, monitors are implicitly non-copyable. 147 148 Another aspect to consider is when a monitor acquires its mutual exclusion. For example, a monitor may need to be passed through multiple helper routines that do not acquire the monitor mutual-exclusion on entry. Pass through can be both generic helper routines (\code{swap}, \code{sort}, etc.) or specific helper routines like the following to implement an atomic counter : 149 150 \begin{lstlisting} 151 mutex struct counter_t { /*...see section §\ref{data}§...*/ }; 152 153 void ?{}(counter_t & nomutex this); //constructor 154 size_t ++?(counter_t & mutex this); //increment 155 156 //need for mutex is platform dependent here 157 void ?{}(size_t * this, counter_t & mutex cnt); //conversion 158 \end{lstlisting} 159 160 Here, the constructor(\code{?\{\}}) uses the \code{nomutex} keyword to signify that it does not acquire the monitor mutual exclusion when constructing. This semantics is because an object not yet constructed should never be shared and therefore does not require mutual exclusion. The prefix increment operator uses \code{mutex} to protect the incrementing process from race conditions. Finally, there is a conversion operator from \code{counter_t} to \code{size_t}. This conversion may or may not require the \code{mutex} key word depending on whether or not reading an \code{size_t} is an atomic operation or not. 161 162 Having both \code{mutex} and \code{nomutex} keywords could be argued to be redundant based on the meaning of a routine having neither of these keywords. For example, given a routine without wualifiers \code{void foo(counter_t & this)} then one could argue that it should default to the safest option \code{mutex}. On the other hand, the option of having routine \code{void foo(counter_t & this)} mean \code{nomutex} is unsafe by default and may easily cause subtle errors. It can be argued that \code{nomutex} is the more "normal" behaviour, the \code{nomutex} keyword effectively stating explicitly that "this routine has nothing special". Another alternative is to make having exactly one of these keywords mandatory, which would provide the same semantics but without the ambiguity of supporting routine \code{void foo(counter_t & this)}. Mandatory keywords would also have the added benefice of being self-documented but at the cost of extra typing. In the end, which solution should be picked is still up for debate. For the reminder of this proposal, the explicit approach is used for clarity. 163 164 The next semantic decision is to establish when mutex/nomutex may be used as a type qualifier. Consider the following declarations: 179 165 \begin{lstlisting} 180 166 int f1(monitor & mutex m); … … 184 170 int f5(graph(monitor*) & mutex m); 185 171 \end{lstlisting} 186 187 The problem is to indentify which object(s) should be acquired. Furthermore we also need to acquire each objects only once. In case of simple routines like \code{f1} and \code{f2} it is easy to identify an exhaustive list of objects to acquire on entering. Adding indirections (\code{f3}) still allows the compiler and programmer to indentify which object will be acquired. However, adding in arrays (\code{f4}) makes it much harder. Array lengths aren't necessarily known in C and even then making sure we only acquire objects once becomes also none trivial. This can be extended to absurd limits like \code{f5} which uses a custom graph of monitors. To keep everyone as sane as possible\cite{Chicken}, this projects imposes the requirement that a routine may only acquire one monitor per parameter and it must be the type of the parameter (ignoring potential qualifiers and indirections). 172 The problem is to indentify which object(s) should be acquired. Furthermore, each object needs to be acquired only once. In the case of simple routines like \code{f1} and \code{f2} it is easy to identify an exhaustive list of objects to acquire on entry. Adding indirections (\code{f3}) still allows the compiler and programmer to indentify which object is acquired. However, adding in arrays (\code{f4}) makes it much harder. Array lengths are not necessarily known in C and even then making sure we only acquire objects once becomes also none trivial. This can be extended to absurd limits like \code{f5}, which uses a graph of monitors. To keep everyone as sane as possible~\cite{Chicken}, this projects imposes the requirement that a routine may only acquire one monitor per parameter and it must be the type of the parameter (ignoring potential qualifiers and indirections). Also note that while routine \code{f3} can be supported, meaning that monitor \code{**m} is be acquired, passing an array to this routine would be type safe and yet result in undefined behavior because only the first element of the array is acquired. However, this ambiguity is part of the C type system with respects to arrays. For this reason, it would also be reasonnable to disallow mutex in the context where arrays may be passed. 188 173 189 174 % ###### # ####### # … … 196 181 197 182 \subsubsection{Data semantics} \label{data} 198 Once the call semantics are established, the next step is to establish data semantics. Indeed, until now a monitor is used simply as a generic handle but in most cases monitors contian shared data. This data should be intrinsic to the monitor declaration to prevent any accidental use of data without its appr ipriate protection. For example here is a more fleshed-out version of the counter showed in \ref{call}:183 Once the call semantics are established, the next step is to establish data semantics. Indeed, until now a monitor is used simply as a generic handle but in most cases monitors contian shared data. This data should be intrinsic to the monitor declaration to prevent any accidental use of data without its appropriate protection. For example, here is a complete version of the counter showed in section \ref{call}: 199 184 \begin{lstlisting} 200 185 mutex struct counter_t { … … 207 192 208 193 int ++?(counter_t & mutex this) { 209 return ++this->value; 210 } 211 194 return ++this.value; 195 } 196 197 //need for mutex is platform dependent here 212 198 void ?{}(int * this, counter_t & mutex cnt) { 213 199 *this = (int)cnt; 214 200 } 215 201 \end{lstlisting} 216 \begin{tabular}{ c c } 217 Thread 1 & Thread 2 \\ 218 \begin{lstlisting} 219 void f(counter_t & mutex c) { 220 for(;;) { 221 sout | (int)c | endl; 222 } 223 } 224 \end{lstlisting} &\begin{lstlisting} 225 void g(counter_t & mutex c) { 226 for(;;) { 227 ++c; 228 } 229 } 230 202 203 This simple counter is used as follows: 204 \begin{center} 205 \begin{tabular}{c @{\hskip 0.35in} c @{\hskip 0.35in} c} 206 \begin{lstlisting} 207 //shared counter 208 counter_t cnt; 209 210 //multiple threads access counter 211 thread 1 : cnt++; 212 thread 2 : cnt++; 213 thread 3 : cnt++; 214 ... 215 thread N : cnt++; 231 216 \end{lstlisting} 232 217 \end{tabular} 233 \\ 234 235 236 This simple counter offers an example of monitor usage. Notice how the counter is used without any explicit synchronisation and yet supports thread-safe semantics for both reading and writting. \\ 237 238 These simple mutual exclusion semantics also naturally expand to multi-monitor calls. 218 \end{center} 219 220 Notice how the counter is used without any explicit synchronisation and yet supports thread-safe semantics for both reading and writting. Unlike object-oriented monitors, where calling a mutex member \emph{implicitly} acquires mutual-exclusion, \CFA uses an explicit mechanism to acquire mutual-exclusion. A consequence of this approach is that it extends to multi-monitor calls. 239 221 \begin{lstlisting} 240 222 int f(MonitorA & mutex a, MonitorB & mutex b); … … 244 226 f(a,b); 245 227 \end{lstlisting} 246 247 This code acquires both locks before entering the critical section. In practice, writing multi-locking routines that can not lead to deadlocks can be very tricky. Having language level support for such feature is therefore a significant asset for \CFA. However, this does have significant repercussions relating to scheduling (see \ref{insched} and \ref{extsched}). Furthermore, the ability to acquire multiple monitors at the same time does incur a significant pitfall even without looking into scheduling. For example : 248 \begin{lstlisting} 249 void foo(A & mutex a, B & mutex a) { 250 //... 251 } 252 253 void bar(A & mutex a, B & nomutex a) 254 //... 255 foo(a, b); 256 //... 257 } 258 259 void baz(A & nomutex a, B & mutex a) 260 //... 261 foo(a, b); 262 //... 263 } 264 \end{lstlisting} 265 266 Recursive mutex routine calls are allowed in \CFA but if not done carefully it can lead to nested monitor call problems\cite{Lister77}. These problems which are a specific implementation of the lock acquiring order problem. In the example above, the user uses implicit ordering in the case of function \code{bar} but explicit ordering in the case of \code{baz}. This subtle mistake can mean that calling these two functions concurrently will lead to deadlocks, depending on the implicit ordering matching the explicit ordering. As shown on several occasion\cit, there isn't really any solutions to this problem, users simply need to be carefull when acquiring multiple monitors at the same time. 228 This code acquires both locks before entering the critical section, called \emph{\gls{group-acquire}}. In practice, writing multi-locking routines that do not lead to deadlocks is tricky. Having language support for such a feature is therefore a significant asset for \CFA. In the case presented above, \CFA guarantees that the order of aquisition is consistent across calls to routines using the same monitors as arguments. However, since \CFA monitors use multi-acquisition locks, users can effectively force the acquiring order. For example, notice which routines use \code{mutex}/\code{nomutex} and how this affects aquiring order : 229 \begin{lstlisting} 230 void foo(A & mutex a, B & mutex b) { //acquire a & b 231 //... 232 } 233 234 void bar(A & mutex a, B & nomutex b) { //acquire a 235 //... 236 foo(a, b); //acquire b 237 //... 238 } 239 240 void baz(A & nomutex a, B & mutex b) { //acquire b 241 //... 242 foo(a, b); //acquire a 243 //... 244 } 245 \end{lstlisting} 246 247 The multi-acquisition monitor lock allows a monitor lock to be acquired by both \code{bar} or \code{baz} and acquired again in \code{foo}. In the calls to \code{bar} and \code{baz} the monitors are acquired in opposite order. such use leads to nested monitor call problems~\cite{Lister77}, which is a specific implementation of the lock acquiring order problem. In the example above, the user uses implicit ordering in the case of function \code{foo} but explicit ordering in the case of \code{bar} and \code{baz}. This subtle mistake means that calling these routines concurrently may lead to deadlock and is therefore undefined behavior. As shown on several occasion\cit, solving this problem requires : 248 \begin{enumerate} 249 \item Dynamically tracking of the monitor-call order. 250 \item Implement rollback semantics. 251 \end{enumerate} 252 253 While the first requirement is already a significant constraint on the system, implementing a general rollback semantics in a C-like language is prohibitively complex \cit. In \CFA, users simply need to be carefull when acquiring multiple monitors at the same time. 267 254 268 255 % ###### ####### ####### # ### # ##### … … 283 270 284 271 \subsubsection{Implementation Details: Interaction with polymorphism} 285 At first glance, interaction between monitors and \CFA's concept of polymorphism seem complexe to support. However, it can be reasoned that entry-point locking can solve most of the issues that could be present with polymorphism. 286 287 First of all, interaction between \code{otype} polymorphism and monitors is impossible since monitors do not support copying. Therefore the main question is how to support \code{dtype} polymorphism. We must remember that monitors' main purpose is to ensure mutual exclusion when accessing shared data. This implies that mutual exclusion is only required for routines that do in fact access shared data. However, since \code{dtype} polymorphism always handle incomplete types (by definition) no \code{dtype} polymorphic routine can access shared data since the data would require knowledge about the type. Therefore the only concern when combining \code{dtype} polymorphism and monitors is to protect access to routines. With callsite-locking, this would require significant amount of work since any \code{dtype} routine could have to obtain some lock before calling a routine. However, with entry-point-locking calling a monitor routine becomes exactly the same as calling it from anywhere else. 272 At first glance, interaction between monitors and \CFA's concept of polymorphism seems complex to support. However, it is shown that entry-point locking can solve most of the issues. 273 274 Before looking into complex control flow, it is important to present the difference between the two acquiring options : \gls{callsite-locking} and \gls{entry-point-locking}, i.e. acquiring the monitors before making a mutex call or as the first instruction of the mutex call. For example: 275 276 \begin{center} 277 \begin{tabular}{|c|c|c|} 278 Code & \gls{callsite-locking} & \gls{entry-point-locking} \\ 279 \CFA & pseudo-code & pseudo-code \\ 280 \hline 281 \begin{lstlisting} 282 void foo(monitor & mutex a) { 283 284 285 286 //Do Work 287 //... 288 289 } 290 291 void main() { 292 monitor a; 293 294 295 296 foo(a); 297 298 } 299 \end{lstlisting} &\begin{lstlisting} 300 foo(& a) { 301 302 303 304 //Do Work 305 //... 306 307 } 308 309 main() { 310 monitor a; 311 //calling routine 312 //handles concurrency 313 acquire(a); 314 foo(a); 315 release(a); 316 } 317 \end{lstlisting} &\begin{lstlisting} 318 foo(& a) { 319 //called routine 320 //handles concurrency 321 acquire(a); 322 //Do Work 323 //... 324 release(a); 325 } 326 327 main() { 328 monitor a; 329 330 331 332 foo(a); 333 334 } 335 \end{lstlisting} 336 \end{tabular} 337 \end{center} 338 339 First of all, interaction between \code{otype} polymorphism and monitors is impossible since monitors do not support copying. Therefore, the main question is how to support \code{dtype} polymorphism. Since a monitor's main purpose is to ensure mutual exclusion when accessing shared data, this implies that mutual exclusion is only required for routines that do in fact access shared data. However, since \code{dtype} polymorphism always handles incomplete types (by definition), no \code{dtype} polymorphic routine can access shared data since the data requires knowledge about the type. Therefore, the only concern when combining \code{dtype} polymorphism and monitors is to protect access to routines. \Gls{callsite-locking} would require a significant amount of work, since any \code{dtype} routine may have to obtain some lock before calling a routine, depending on whether or not the type passed is a monitor. However, with \gls{entry-point-locking} calling a monitor routine becomes exactly the same as calling it from anywhere else. 340 341 288 342 289 343 % ### # # ####### ##### ##### # # ####### ###### … … 296 350 297 351 \subsection{Internal scheduling} \label{insched} 298 Monitors should also be able to schedule what threads access it as a mean of synchronization. Internal scheduling is one of the simple examples of such a feature. It allows users to declare condition variables and wait for them to be signaled. Here is a simple example of such a technique :352 Monitors also need to schedule waiting threads internally as a mean of synchronization. Internal scheduling is one of the simple examples of such a feature. It allows users to declare condition variables and have threads wait and signaled from them. Here is a simple example of such a technique : 299 353 300 354 \begin{lstlisting} … … 314 368 \end{lstlisting} 315 369 316 Here routine \code{foo} waits on the \code{signal} from \code{bar} before making further progress, effectively ensuring a basic ordering. This semantic can easily be extended to multi-monitor calls by offering the same guarantee. 317 370 Note that in \CFA, \code{condition} have no particular need to be stored inside a monitor, beyond any software engineering reasons. Here routine \code{foo} waits for the \code{signal} from \code{bar} before making further progress, effectively ensuring a basic ordering. This semantic can easily be extended to multi-monitor calls by offering the same guarantee. 318 371 \begin{center} 319 372 \begin{tabular}{ c @{\hskip 0.65in} c } … … 321 374 \begin{lstlisting} 322 375 void foo(monitor & mutex a, 323 monitor & mutex b) {376 monitor & mutex b) { 324 377 //... 325 378 wait(a.e); … … 330 383 \end{lstlisting} &\begin{lstlisting} 331 384 void bar(monitor & mutex a, 332 monitor & mutex b) {385 monitor & mutex b) { 333 386 signal(a.e); 334 387 } … … 340 393 \end{tabular} 341 394 \end{center} 342 343 A direct extension of the single monitor semantics would be to release all locks when waiting and transferring ownership of all locks when signalling. However, for the purpose of synchronization it may be usefull to only release some of the locks but keep others. On the technical side, partially releasing lock is feasible but from the user perspective a choice must be made for the syntax of this feature. It is possible to do without any extra syntax by relying on order of acquisition (Note that here the use of helper routines is irrelevant, only routines the acquire mutual exclusion have an impact on internal scheduling): 395 A direct extension of the single monitor semantics is to release all locks when waiting and transferring ownership of all locks when signalling. However, for the purpose of synchronization it may be usefull to only release some of the locks but keep others. It is possible to support internal scheduling and \gls{group-acquire} without any extra syntax by relying on order of acquisition. Here is an example of the different contexts in which internal scheduling can be used. (Note that here the use of helper routines is irrelevant, only routines acquire mutual exclusion have an impact on internal scheduling): 344 396 345 397 \begin{center} … … 350 402 condition e; 351 403 404 //acquire a & b 352 405 void foo(monitor & mutex a, 353 monitor & mutex b) { 354 wait(e); 406 monitor & mutex b) { 407 408 wait(e); //release a & b 355 409 } 356 410 … … 364 418 condition e; 365 419 420 //acquire a 366 421 void bar(monitor & mutex a, 367 monitor & nomutex b) {422 monitor & nomutex b) { 368 423 foo(a,b); 369 424 } 370 425 426 //acquire a & b 371 427 void foo(monitor & mutex a, 372 monitor & mutex b) {373 wait(e); 428 monitor & mutex b) { 429 wait(e); //release a & b 374 430 } 375 431 … … 378 434 condition e; 379 435 436 //acquire a 380 437 void bar(monitor & mutex a, 381 monitor & nomutex b) { 382 foo(a,b); 383 } 384 438 monitor & nomutex b) { 439 baz(a,b); 440 } 441 442 //acquire b 385 443 void baz(monitor & nomutex a, 386 monitor & mutex b) {387 wait(e); 444 monitor & mutex b) { 445 wait(e); //release b 388 446 } 389 447 … … 393 451 \end{center} 394 452 395 This can be interpreted in two different ways : 396 \begin{flushleft} 397 \begin{enumerate} 398 \item \code{wait} atomically releases the monitors acquired by the inner-most routine, \underline{ignoring} nested calls. 399 \item \code{wait} atomically releases the monitors acquired by the inner-most routine, \underline{considering} nested calls. 400 \end{enumerate} 401 \end{flushleft} 402 While the difference between these two is subtle, it has a significant impact. In the first case it means that the calls to \code{foo} would behave the same in Context 1 and 2. This semantic would also mean that the call to \code{wait} in routine \code{baz} would only release \code{monitor b}. While this may seem intuitive with these examples, it does have one significant implication, it creates a strong distinction between acquiring multiple monitors in sequence and acquiring the same monitors simulatenously, i.e. : 453 Context 1 is the simplest way of acquiring more than one monitor (\gls{group-acquire}), using a routine with multiple parameters having the \code{mutex} keyword. Context 2 also uses \gls{group-acquire} as well in routine \code{foo}. However, the routine is called by routine \code{bar}, which only acquires monitor \code{a}. Since monitors can be acquired multiple times this does not cause a deadlock by itself but it does force the acquiring order to \code{a} then \code{b}. Context 3 also forces the acquiring order to be \code{a} then \code{b} but does not use \gls{group-acquire}. The previous example tries to illustrate the semantics that must be established to support releasing monitors in a \code{wait} statement. In all cases, the behavior of the wait statment is to release all the locks that were acquired my the inner-most monitor call. That is \code{a & b} in context 1 and 2 and \code{b} only in context 3. Here are a few other examples of this behavior. 454 403 455 404 456 \begin{center} 405 \begin{tabular}{c @{\hskip 0.35in} c @{\hskip 0.35in} c} 406 \begin{lstlisting} 407 enterMonitor(a); 408 enterMonitor(b); 409 // do stuff 410 leaveMonitor(b); 411 leaveMonitor(a); 412 \end{lstlisting} & != &\begin{lstlisting} 413 enterMonitor(a); 414 enterMonitor(a, b); 415 // do stuff 416 leaveMonitor(a, b); 417 leaveMonitor(a); 457 \begin{tabular}{|c|c|c|} 458 \begin{lstlisting} 459 condition e; 460 461 //acquire b 462 void foo(monitor & nomutex a, 463 monitor & mutex b) { 464 bar(a,b); 465 } 466 467 //acquire a 468 void bar(monitor & mutex a, 469 monitor & nomutex b) { 470 471 wait(e); //release a 472 //keep b 473 } 474 475 foo(a, b); 476 \end{lstlisting} &\begin{lstlisting} 477 condition e; 478 479 //acquire a & b 480 void foo(monitor & mutex a, 481 monitor & mutex b) { 482 bar(a,b); 483 } 484 485 //acquire b 486 void bar(monitor & mutex a, 487 monitor & nomutex b) { 488 489 wait(e); //release b 490 //keep a 491 } 492 493 foo(a, b); 494 \end{lstlisting} &\begin{lstlisting} 495 condition e; 496 497 //acquire a & b 498 void foo(monitor & mutex a, 499 monitor & mutex b) { 500 bar(a,b); 501 } 502 503 //acquire none 504 void bar(monitor & nomutex a, 505 monitor & nomutex b) { 506 507 wait(e); //release a & b 508 //keep none 509 } 510 511 foo(a, b); 418 512 \end{lstlisting} 419 513 \end{tabular} 420 514 \end{center} 421 422 This is not intuitive because even if both methods display the same monitors state both inside and outside the critical section respectively, the behavior is different. Furthermore, the actual acquiring order will be exaclty the same since acquiring a monitor from inside its mutual exclusion is a no-op. This means that even if the data and the actual control flow are the same using both methods, the behavior of the \code{wait} will be different. The alternative is option 2, that is releasing acquired monitors, \underline{considering} nesting. This solves the issue of having the two acquiring method differ at the cost of making routine \code{foo} behave differently depending on from which context it is called (Context 1 or 2). Indeed in Context 2, routine \code{foo} actually behaves like routine \code{baz} rather than having the same behavior than in Context 1. The fact that both implicit approaches can be unintuitive depending on the perspective may be a sign that the explicit approach is superior. For this reason this \CFA does not support implicit monitor releasing and uses explicit semantics. 423 \\ 424 425 The following examples shows three alternatives of explicit wait semantics : 426 \\ 427 515 Note the right-most example is actually a trick pulled on the reader. Monitor state information is stored in thread local storage rather then in the routine context, which means that helper routines and other \code{nomutex} routines are invisible to the runtime system in regards to concurrency. This means that in the right-most example, the routine parameters are completly unnecessary. However, calling this routine from outside a valid monitor context is undefined. 516 517 These semantics imply that in order to release of subset of the monitors currently held, users must write (and name) a routine that only acquires the desired subset and simply calls wait. While users can use this method, \CFA offers the \code{wait_release}\footnote{Not sure if an overload of \code{wait} would work...} which will release only the specified monitors. In the center previous examples, the code in the center uses the \code{bar} routine to only release monitor \code{b}. Using the \code{wait_release} helper, this can be rewritten without having the name two routines : 428 518 \begin{center} 429 \begin{tabular}{|c|c|c|} 430 Case 1 & Case 2 & Case 3 \\ 431 Branding on construction & Explicit release list & Explicit ignore list \\ 432 \hline 433 \begin{lstlisting} 434 void foo(monitor & mutex a, 435 monitor & mutex b, 436 condition & c) 437 { 438 // Releases monitors 439 // branded in ctor 440 wait(c); 441 } 442 443 monitor a; 444 monitor b; 445 condition1 c1 = {a}; 446 condition2 c2 = {a, b}; 447 448 //Will release only a 449 foo(a,b,c1); 450 451 //Will release a and b 452 foo(a,b,c2); 519 \begin{tabular}{ c c c } 520 \begin{lstlisting} 521 condition e; 522 523 //acquire a & b 524 void foo(monitor & mutex a, 525 monitor & mutex b) { 526 bar(a,b); 527 } 528 529 //acquire b 530 void bar(monitor & mutex a, 531 monitor & nomutex b) { 532 533 wait(e); //release b 534 //keep a 535 } 536 537 foo(a, b); 453 538 \end{lstlisting} &\begin{lstlisting} 454 void foo(monitor & mutex a, 455 monitor & mutex b, 456 condition & c) 457 { 458 // Releases monitor a 459 // Holds monitor b 460 waitRelease(c, [a]); 461 } 462 463 monitor a; 464 monitor b; 465 condition c; 466 467 468 469 foo(a,b,c); 470 471 472 539 => 473 540 \end{lstlisting} &\begin{lstlisting} 474 void foo(monitor & mutex a, 475 monitor & mutex b, 476 condition & c) 477 { 478 // Releases monitor a 479 // Holds monitor b 480 waitHold(c, [b]); 481 } 482 483 monitor a; 484 monitor b; 485 condition c; 486 487 488 489 foo(a,b,c); 490 491 492 541 condition e; 542 543 //acquire a & b 544 void foo(monitor & mutex a, 545 monitor & mutex b) { 546 wait_release(e,b); //release b 547 //keep a 548 } 549 550 foo(a, b); 493 551 \end{lstlisting} 494 552 \end{tabular} 495 553 \end{center} 496 (Note : Case 2 and 3 use tuple semantics to pass a variable length list of elements.) 497 \\ 498 499 All these cases have their pros and cons. Case 1 is more distinct because it means programmers need to be carefull about where the condition is initialized as well as where it is used. On the other hand, it is very clear and explicitly states which monitor is released and which monitor stays acquired. This is similar to Case 2, which releases only the monitors explictly listed. However, in Case 2, calling the \code{wait} routine instead of the \code{waitRelease} routine releases all the acquired monitor. The Case 3 is an improvement on that since it releases all the monitors except those specified. The result is that the \code{wait} routine can be written as follows : 500 \begin{lstlisting} 501 void wait(condition & cond) { 502 waitHold(cond, []); 503 } 504 \end{lstlisting} 505 This alternative offers nice and consistent behavior between \code{wait} and \code{waitHold}. However, one large pitfall is that mutual exclusion can now be violated by calls to library code. Indeed, even if the following example seems benign there is one significant problem : 506 \begin{lstlisting} 507 monitor global; 508 509 extern void doStuff(); //uses global 510 511 void foo(monitor & mutex m) { 512 //... 513 doStuff(); //warning can release monitor m 514 //... 515 } 516 517 foo(global); 518 \end{lstlisting} 519 520 Indeed, if Case 2 or 3 are chosen it any code can violate the mutual exclusion of the calling code by issuing calls to \code{wait} or \code{waitHold} in a nested monitor context. Case 2 can be salvaged by removing the \code{wait} routine from the API but Case 3 cannot prevent users from calling \code{waitHold(someCondition, [])}. For this reason the syntax proposed in Case 3 is rejected. Note that the syntax proposed in case 1 and 2 are not exclusive. Indeed, by supporting two types of condition both cases can be supported : 521 \begin{lstlisting} 522 struct condition { /*...*/ }; 523 524 // Second argument is a variable length tuple. 525 void wait(condition & cond, [...] monitorsToRelease); 526 void signal(condition & cond); 527 528 struct conditionN { /*...*/ }; 529 530 void ?{}(conditionN* this, /*list of N monitors to release*/); 531 void wait(conditionN & cond); 532 void signal(conditionN & cond); 533 \end{lstlisting} 534 535 Regardless of the option chosen for wait semantics, signal must be symmetrical. In all cases, signal only needs a single parameter, the condition variable that needs to be signalled. But \code{signal} needs to be called from the same monitor(s) that call to \code{wait}. Otherwise, mutual exclusion cannot be properly transferred back to the waiting monitor. 536 537 Finally, an additionnal semantic which can be very usefull is the \code{signalBlock} routine. This routine behaves like signal for all of the semantics discussed above, but with the subtelty that mutual exclusion is transferred to the waiting task immediately rather than wating for the end of the critical section. 554 555 Regardless of the context in which the \code{wait} statement is used, \code{signal} must be called holding the same set of monitors. In all cases, signal only needs a single parameter, the condition variable that needs to be signalled. But \code{signal} needs to be called from the same monitor(s) that call to \code{wait}. Otherwise, mutual exclusion cannot be properly transferred back to the waiting monitor. 556 557 Finally, an additional semantic which can be very usefull is the \code{signal_block} routine. This routine behaves like signal for all of the semantics discussed above, but with the subtelty that mutual exclusion is transferred to the waiting task immediately rather than wating for the end of the critical section. 538 558 \\ 539 559 … … 545 565 % # # # # ### # # # # # # # # # 546 566 % ####### # # # ### ##### ##### # # ####### ###### 547 567 \newpage 548 568 \subsection{External scheduling} \label{extsched} 549 A s one might expect, the alternative to Internal scheduling is to use External scheduling instead. This method is somewhat more robust to deadlocks since one of the threads keeps a relatively tight control on scheduling. Indeed, as the following examples will demonstrate, external scheduling allows users to wait for events from other threads without the concern of unrelated events occuring. External scheduling can generally be done either in terms of control flow (ex: \uC) or in terms of data (ex: Go). Of course, both of these paradigms have their own strenghts and weaknesses but for this project control flow semantics where chosen to stay consistent with the rest of the languages semantics. Two challenges specific to \CFA arise when trying to add external scheduling with loose object definitions and multi-monitor routines. The following example shows whata simple use \code{accept} versus \code{wait}/\code{signal} and its advantages.569 An alternative to internal scheduling is to use external scheduling instead. This method is more constrained and explicit which may help users tone down the undeterministic nature of concurrency. Indeed, as the following examples demonstrates, external scheduling allows users to wait for events from other threads without the concern of unrelated events occuring. External scheduling can generally be done either in terms of control flow (ex: \uC) or in terms of data (ex: Go). Of course, both of these paradigms have their own strenghts and weaknesses but for this project control flow semantics where chosen to stay consistent with the rest of the languages semantics. Two challenges specific to \CFA arise when trying to add external scheduling with loose object definitions and multi-monitor routines. The following example shows a simple use \code{accept} versus \code{wait}/\code{signal} and its advantages. 550 570 551 571 \begin{center} … … 565 585 566 586 public: 567 void f() ;587 void f() { /*...*/ } 568 588 void g() { _Accept(f); } 569 589 private: … … 573 593 \end{center} 574 594 575 In the case of internal scheduling, the call to \code{wait} only guarantees that \code{g} was the last routine to access the monitor. This intails that the routine \code{f} may have acquired mutual exclusion several times while routine \code{h} was waiting. On the other hand, external scheduling guarantees that while routine \code{h} was waiting, no routine other than \code{g} could acquire the monitor.595 In the case of internal scheduling, the call to \code{wait} only guarantees that \code{g} is the last routine to access the monitor. This intails that the routine \code{f} may have acquired mutual exclusion several times while routine \code{h} was waiting. On the other hand, external scheduling guarantees that while routine \code{h} was waiting, no routine other than \code{g} could acquire the monitor. 576 596 \\ 577 597 … … 756 776 % # # # # # # # ####### ####### ####### ####### ### ##### # # 757 777 \section{Parallelism} 758 Historically, computer performance was about processor speeds and instructions count. However, with heat dissipation being a n ever growing challenge, parallelism has become the new source of greatest performance \cite{Sutter05, Sutter05b}. In this decade, it is not longer reasonnable to create high-performance application without caring about parallelism. Indeed, parallelism is an important aspect of performance and more specifically throughput and hardware utilization. The lowest level approach of parallelism is to use \glspl{kthread}. However since these have significant costs and limitations \glspl{kthread} are now mostly used as an implementation tool rather than a user oriented one. There are several alternatives to solve these issues which all have strengths and weaknesses.778 Historically, computer performance was about processor speeds and instructions count. However, with heat dissipation being a direct consequence of speed increase, parallelism has become the new source for increased performance~\cite{Sutter05, Sutter05b}. In this decade, it is not longer reasonnable to create a high-performance application without caring about parallelism. Indeed, parallelism is an important aspect of performance and more specifically throughput and hardware utilization. The lowest-level approach of parallelism is to use \glspl{kthread} in combination with semantics like \code{fork}, \code{join}, etc. However, since these have significant costs and limitations, \glspl{kthread} are now mostly used as an implementation tool rather than a user oriented one. There are several alternatives to solve these issues that all have strengths and weaknesses. While there are many variations of the presented paradigms, most of these variations do not actually change the guarantees or the semantics, they simply move costs in order to achieve better performance for certain workloads. 759 779 760 780 \subsection{User-level threads} 761 A direct improvement on the \gls{kthread} approach is to use \glspl{uthread}. These threads offer most of the same features that the operating system already provide but can be used on a much larger scale. This is the most powerfull solution as it allows all the features of multi-threading while removing several of the more expensives costs of using kernel threads. The down side is that almost none of the low-level threading complexities are hidden, users still have to think about data races, deadlocks and synchronization issues. This can be somewhat alleviated by a concurrency toolkit with strong garantees but the parallelism toolkit offers very little to reduce complexity in itself. 762 763 Examples of languages that support are Java\cite{Java}, Haskell\cite{Haskell} and \uC\cite{uC++book}. 781 A direct improvement on the \gls{kthread} approach is to use \glspl{uthread}. These threads offer most of the same features that the operating system already provide but can be used on a much larger scale. This approach is the most powerfull solution as it allows all the features of multi-threading, while removing several of the more expensives costs of using kernel threads. The down side is that almost none of the low-level threading problems are hidden, users still have to think about data races, deadlocks and synchronization issues. These issues can be somewhat alleviated by a concurrency toolkit with strong garantees but the parallelism toolkit offers very little to reduce complexity in itself. 782 783 Examples of languages that support \glspl{uthread} are Erlang~\cite{Erlang} and \uC~\cite{uC++book}. 784 785 \subsubsection{Fibers : user-level threads without preemption} 786 A popular varient of \glspl{uthread} is what is often reffered to as \glspl{fiber}. However, \glspl{fiber} do not present meaningful semantical differences with \glspl{uthread}. Advocates of \glspl{fiber} list their high performance and ease of implementation as majors strenghts of \glspl{fiber} but the performance difference between \glspl{uthread} and \glspl{fiber} is controversial and the ease of implementation, while true, is a weak argument in the context of language design. Therefore this proposal largely ignore fibers. 787 788 An example of a language that uses fibers is Go~\cite{Go} 764 789 765 790 \subsection{Jobs and thread pools} 766 The approach on the opposite end of the spectrum is to base parallelism on \glspl{job}. Indeed, \glspl{job} offer limited flexibility but at the benefit of a simpler user interface. In \gls{job} based systems users express parallelism as units of work and the dependency graph (either explicit or implicit) that tie them together. This means users need not to worry about concurrency but significantly limits the interaction that can occur between different jobs. Indeed, any \gls{job} that blocks also blocks the underlying \gls{kthread}, this effectively mean the CPU utilization, and therefore throughput, will suffer noticeably. 767 The golden standard of this implementation is Intel's TBB library\cite{TBB}. 768 769 \subsection{Fibers : user-level threads without preemption} 770 Finally, in the middle of the flexibility versus complexity spectrum lay \glspl{fiber} which offer \glspl{uthread} without the complexity of preemption. This means users don't have to worry about other \glspl{fiber} suddenly executing between two instructions which signficantly reduces complexity. However, any call to IO or other concurrency primitives can lead to context switches. Furthermore, users can also block \glspl{fiber} in the middle of their execution without blocking a full processor core. This means users still have to worry about mutual exclusion, deadlocks and race conditions in their code, raising the complexity significantly. 771 An example of a language that uses fibers is Go\cite{Go} 791 The approach on the opposite end of the spectrum is to base parallelism on \glspl{pool}. Indeed, \glspl{pool} offer limited flexibility but at the benefit of a simpler user interface. In \gls{pool} based systems, users express parallelism as units of work and a dependency graph (either explicit or implicit) that tie them together. This approach means users need not worry about concurrency but significantly limits the interaction that can occur among jobs. Indeed, any \gls{job} that blocks also blocks the underlying worker, which effectively means the CPU utilization, and therefore throughput, suffers noticeably. It can be argued that a solution to this problem is to use more workers than available cores. However, unless the number of jobs and the number of workers are comparable, having a significant amount of blocked jobs always results in idles cores. 792 793 The gold standard of this implementation is Intel's TBB library~\cite{TBB}. 772 794 773 795 \subsection{Paradigm performance} 774 While the choice between the three paradigms listed above may have significant performance implication, it is difficult to pin the performance implications of chosing a model at the language level. Indeed, in many situations one of these paradigms will show better performance but it all strongly depends on the usage. Having mostly indepent units of work to execute almost guarantess that the \gls{job} based system will have the best performance. However, add interactions between jobs and the processor utilisation might suffer. User-level threads may allow maximum ressource utilisation but context switches will be more expansive and it is also harder for users to get perfect tunning. As with every example, fibers sit somewhat in the middle of the spectrum. Furthermore, if the units of uninterrupted work are large enough the paradigm choice will belargely amorticised by the actual work done.796 While the choice between the three paradigms listed above may have significant performance implication, it is difficult to pindown the performance implications of chosing a model at the language level. Indeed, in many situations one of these paradigms may show better performance but it all strongly depends on the workload. Having a large amount of mostly independent units of work to execute almost guarantess that the \gls{pool} based system has the best performance thanks to the lower memory overhead. However, interactions between jobs can easily exacerbate contention. User-level threads allow fine-grain context switching, which results in better resource utilisation, but context switches will be more expansive and the extra control means users need to tweak more variables to get the desired performance. Furthermore, if the units of uninterrupted work are large enough the paradigm choice is largely amorticised by the actual work done. 775 797 776 798 % ##### ####### # ####### ###### ###### … … 783 805 784 806 \section{\CFA 's Thread Building Blocks} 785 As a system level language, \CFA should offer both performance and flexibilty as its primary goals, simplicity and user-friendliness being a secondary concern. Therefore, the core of parallelism in \CFA should prioritize power and efficiency. With this said, it is possible to deconstruct the three paradigms details aboved in order to get simple building blocks. Here is a table showing the core caracteristics of the mentionned paradigms : 786 \begin{center} 787 \begin{tabular}[t]{| r | c | c |} 788 \cline{2-3} 789 \multicolumn{1}{ c| }{} & Has a stack & Preemptive \\ 790 \hline 791 \Glspl{job} & X & X \\ 792 \hline 793 \Glspl{fiber} & \checkmark & X \\ 794 \hline 795 \Glspl{uthread} & \checkmark & \checkmark \\ 796 \hline 797 \end{tabular} 798 \end{center} 799 800 As shown in section \ref{cfaparadigms} these different blocks being available in \CFA it is trivial to reproduce any of these paradigm. 807 As a system-level language, \CFA should offer both performance and flexibilty as its primary goals, simplicity and user-friendliness being a secondary concern. Therefore, the core of parallelism in \CFA should prioritize power and efficiency. With this said, deconstructing popular paradigms in order to get simple building blocks yields \glspl{uthread} as the core parallelism block. \Glspl{pool} and other parallelism paradigms can then be built on top of the underlying threading model. 801 808 802 809 % ####### # # ###### ####### # ###### ##### … … 809 816 810 817 \subsection{Thread Interface} 811 The basic building blocks of \CFA are \glspl{cfathread}. By default these are implemented as \glspl{uthread} and as such offer a flexible and lightweight threading interface (lightweight comparatievely to \glspl{kthread}). A thread can be declared using a struct declaration prefix with the\code{thread} as follows :818 The basic building blocks of \CFA are \glspl{cfathread}. By default these are implemented as \glspl{uthread}, and as such, offer a flexible and lightweight threading interface (lightweight compared to \glspl{kthread}). A thread can be declared using a struct declaration with prefix \code{thread} as follows : 812 819 813 820 \begin{lstlisting} … … 815 822 \end{lstlisting} 816 823 817 Obviously, for this thread implementation to be usefull it must run some user code. Several other threading interfaces use some function pointer representation as the interface of threads (for example : \Csharp \cite{Csharp} and Scala \cite{Scala}). However, we consider that statically tying a \code{main} routine to a thread superseeds this approach. Since the \code{main} routine is definetely a special routine in \CFA, we can reuse the existing syntax for declaring routines with unordinary name, i.e. operator overloading. As such the \code{main} routine of a thread can be defined as such:824 Obviously, for this thread implementation to be usefull it must run some user code. Several other threading interfaces use a function-pointer representation as the interface of threads (for example : \Csharp~\cite{Csharp} and Scala~\cite{Scala}). However, this proposal considers that statically tying a \code{main} routine to a thread superseeds this approach. Since the \code{main} routine is already a special routine in \CFA (where the program begins), the existing syntax for declaring routines names with special semantics can be extended, i.e. operator overloading. As such the \code{main} routine of a thread can be defined as : 818 825 \begin{lstlisting} 819 826 thread struct foo {}; 820 827 821 void ?main( threadfoo* this) {822 /*... Some useful code ...*/823 } 824 \end{lstlisting} 825 826 With these semantics it is trivial to write a thread type that takes a function pointer as parameter and executes it on its stack asynchronously :828 void ?main(foo* this) { 829 sout | "Hello World!" | endl; 830 } 831 \end{lstlisting} 832 833 In this example, threads of type \code{foo} will start there execution in the \code{void ?main(foo*)} routine which in this case prints \code{"Hello World!"}. While this proposoal encourages this approach which is enforces strongly type programming. Users may prefer to use the routine based thread semantics for the sake of simplicity. With these semantics it is trivial to write a thread type that takes a function pointer as parameter and executes it on its stack asynchronously : 827 834 \begin{lstlisting} 828 835 typedef void (*voidFunc)(void); … … 833 840 834 841 //ctor 835 void ?{}( threadFuncRunner* this, voidFunc inFunc) {842 void ?{}(FuncRunner* this, voidFunc inFunc) { 836 843 func = inFunc; 837 844 } 838 845 839 846 //main 840 void ?main( threadFuncRunner* this) {847 void ?main(FuncRunner* this) { 841 848 this->func(); 842 849 } 843 850 \end{lstlisting} 844 851 845 % In this example \code{func} is a function pointer stored in \acrfull{tls}, which is \CFA is both easy to use and completly typesafe. 846 847 Of course for threads to be useful, it must be possible to start and stop threads and wait for them to complete execution. While using an \acrshort{api} such as \code{fork} and \code{join} is relatively common in the literature, such an interface is not needed. Indeed, the simplest approach is to use \acrshort{raii} principles and have threads \code{fork} once the constructor has completed and \code{join} before the destructor runs. 848 \begin{lstlisting} 849 thread struct FuncRunner; //FuncRunner declared above 850 851 void world() { 852 Of course for threads to be useful, it must be possible to start and stop threads and wait for them to complete execution. While using an \acrshort{api} such as \code{fork} and \code{join} is relatively common in the literature, such an interface is unnecessary. Indeed, the simplest approach is to use \acrshort{raii} principles and have threads \code{fork} once the constructor has completed and \code{join} before the destructor runs. 853 \begin{lstlisting} 854 thread struct World; //FuncRunner declared above 855 856 void ?main(thread World* this) { 852 857 sout | "World!" | endl; 853 858 } 854 859 855 860 void main() { 856 FuncRunner run = {world};861 World w; 857 862 //Thread run forks here 858 863 … … 863 868 } 864 869 \end{lstlisting} 865 This semantic has several advantages over explicit semantics : typesafety is guaranteed, any thread will always be started and stopped exaclty once and users can't make any progamming errors. Furthermore it naturally follows the memory allocation semantics which means users don't need to learn multiple semantics. 866 867 These semantics also naturally scale to multiple threads meaning basic synchronisation is very simple : 870 This semantic has several advantages over explicit semantics : typesafety is guaranteed, a thread is always started and stopped exaclty once and users cannot make any progamming errors. However, one of the apparent drawbacks of this system is that threads now always form a lattice, that is they are always destroyed in opposite order of construction. While this seems like a significant limitation, existing \CFA semantics can solve this problem. Indeed, by using dynamic allocation to create threads will naturally let threads outlive the scope in which the thread was created much like dynamically allocating memory will let objects outlive the scope in which thy were created : 871 868 872 \begin{lstlisting} 869 873 thread struct MyThread { … … 872 876 873 877 //ctor 874 void ?{}(thread MyThread* this) {} 878 void ?{}(MyThread* this, 879 bool is_special = false) { 880 //... 881 } 875 882 876 883 //main 877 void ?main(thread MyThread* this) { 884 void ?main(MyThread* this) { 885 //... 886 } 887 888 void foo() { 889 MyThread* special_thread; 890 { 891 MyThread thrds = {false}; 892 //Start a thread at the beginning of the scope 893 894 DoStuff(); 895 896 //create a other thread that will outlive the thread in this scope 897 special_thread = new MyThread{true}; 898 899 //Wait for the thread to finish 900 } 901 DoMoreStuff(); 902 903 //Now wait for the special 904 } 905 \end{lstlisting} 906 907 Another advantage of this semantic is that it naturally scale to multiple threads meaning basic synchronisation is very simple : 908 909 \begin{lstlisting} 910 thread struct MyThread { 911 //... 912 }; 913 914 //ctor 915 void ?{}(MyThread* this) {} 916 917 //main 918 void ?main(MyThread* this) { 878 919 //... 879 920 } … … 889 930 \end{lstlisting} 890 931 932 \subsection{Coroutines : A stepping stone}\label{coroutine} 933 While the main focus of this proposal is concurrency and paralellism, it is important to adress coroutines which are actually a significant underlying aspect of the concurrency system. Indeed, while having nothing todo with parallelism and arguably very little to do with concurrency, coroutines need to deal with context-switchs and and other context management operations. Therefore, this proposal includes coroutines both as an intermediate step for the implementation of threads and a first class feature of \CFA. 934 935 The core API of coroutines revolve around two features : independent stacks and suspedn/resume. Much like threads the syntax for declaring a coroutine is declaring a type and a main routine for it to start : 936 \begin{lstlisting} 937 coroutine struct MyCoroutine { 938 //... 939 }; 940 941 //ctor 942 void ?{}(MyCoroutine* this) { 943 944 } 945 946 //main 947 void ?main(MyCoroutine* this) { 948 sout | "Hello World!" | endl; 949 } 950 \end{lstlisting} 951 952 One a coroutine is created, users can context switch to it using \code{suspend} and come back using \code{resume}. Here is an example of a solution to the fibonnaci problem using coroutines : 953 \begin{lstlisting} 954 coroutine struct Fibonacci { 955 int fn; // used for communication 956 }; 957 958 void ?main(Fibonacci* this) { 959 int fn1, fn2; // retained between resumes 960 this->fn = 0; 961 fn1 = this->fn; 962 suspend(this); // return to last resume 963 964 this->fn = 1; 965 fn2 = fn1; 966 fn1 = this->fn; 967 suspend(this); // return to last resume 968 969 for ( ;; ) { 970 this->fn = fn1 + fn2; 971 fn2 = fn1; 972 fn1 = this->fn; 973 suspend(this); // return to last resume 974 } 975 } 976 977 int next(Fibonacci& this) { 978 resume(&this); // transfer to last suspend 979 return this.fn; 980 } 981 982 void main() { 983 Fibonacci f1, f2; 984 for ( int i = 1; i <= 10; i += 1 ) { 985 sout | next(f1) | '§\verb+ +§' | next(f2) | endl; 986 } 987 } 988 \end{lstlisting} 989 891 990 \newpage 892 \ large{\textbf{WORK IN PROGRESS}}991 \bf{WORK IN PROGRESS} 893 992 \subsection{The \CFA Kernel : Processors, Clusters and Threads}\label{kernel} 894 993 -
doc/proposals/concurrency/glossary.tex
r3a2128f r1f44196 1 1 \makeglossaries 2 3 \longnewglossaryentry{callsite-locking} 4 {name={callsite-locking}} 5 { 6 Locking done by the calling routine. With this technique, a routine calling a monitor routine will aquire the monitor \emph{before} making the call to the actuall routine. 7 } 8 9 \longnewglossaryentry{entry-point-locking} 10 {name={entry-point-locking}} 11 { 12 Locking done by the called routine. With this technique, a monitor routine called by another routine will aquire the monitor \emph{after} entering the routine body but prior to any other code. 13 } 14 15 \longnewglossaryentry{group-acquire} 16 {name={bulked acquiring}} 17 { 18 Implicitly acquiring several monitors when entering a monitor. 19 } 20 21 2 22 \longnewglossaryentry{uthread} 3 23 {name={user-level thread}} … … 30 50 31 51 \textit{Synonyms : Tasks.} 52 } 53 54 \longnewglossaryentry{pool} 55 {name={thread-pool}} 56 { 57 Group of homogeneuous threads that loop executing units of works after another. 58 59 \textit{Synonyms : } 32 60 } 33 61 -
doc/proposals/concurrency/version
r3a2128f r1f44196 1 0. 4.991 0.7.48 -
doc/working/resolver_design.md
r3a2128f r1f44196 1382 1382 hypothesis needs to be empirically validated. 1383 1383 1384 Another approach would be to abandon expression-tree ordering for 1385 subexpression matching, and order by "most constrained symbol"; symbols would 1386 be more constrained if there were fewer matching declarations, fewer 1387 subexpressions yet to resolve, or possibly fewer possible types the expression 1388 could resolve to. Ordering the expressions in a priority-queue by this metric 1389 would not necessarily produce a top-down or a bottom-up order, but would add 1390 opportunities for pruning based on memoized upper and lower bounds. 1391 1384 1392 Both Baker and Cormack explicitly generate all possible interpretations of a 1385 1393 given expression; thinking of the set of interpretations of an expression as a -
src/CodeGen/CodeGenerator.cc
r3a2128f r1f44196 307 307 } else { 308 308 // no address-of operator, so must be a pointer - add dereference 309 // NOTE: if the assertion starts to trigger, check that the application expr isn't being shared. 310 // Since its arguments are modified here, this assertion most commonly triggers when the application 311 // is visited multiple times. 309 312 UntypedExpr * newExpr = new UntypedExpr( new NameExpr( "*?" ) ); 310 313 newExpr->get_args().push_back( *arg ); 311 assert( (*arg)->get_results().size() == 1 ); 312 Type * type = InitTweak::getPointerBase( (*arg)->get_results().front() ); 313 assert( type ); 314 newExpr->get_results().push_back( type->clone() ); 314 Type * type = InitTweak::getPointerBase( (*arg)->get_result() ); 315 assertf( type, "First argument to a derefence must be a pointer. Ensure that expressions are not being shared." ); 316 newExpr->set_result( type->clone() ); 315 317 *arg = newExpr; 316 318 } // if … … 527 529 extension( castExpr ); 528 530 output << "("; 529 if ( castExpr->get_result s().empty() ) {531 if ( castExpr->get_result()->isVoid() ) { 530 532 output << "(void)" ; 531 } else if ( ! castExpr->get_result s().front()->get_isLvalue() ) {533 } else if ( ! castExpr->get_result()->get_isLvalue() ) { 532 534 // at least one result type of cast, but not an lvalue 533 535 output << "("; 534 output << genType( castExpr->get_result s().front(), "" );536 output << genType( castExpr->get_result(), "" ); 535 537 output << ")"; 536 538 } else { … … 640 642 } 641 643 642 void CodeGenerator::visit( TupleExpr * tupleExpr ) { }644 void CodeGenerator::visit( TupleExpr * tupleExpr ) { assert( false ); } 643 645 644 646 void CodeGenerator::visit( TypeExpr * typeExpr ) {} … … 654 656 asmExpr->get_operand()->accept( *this ); 655 657 output << " )"; 658 } 659 660 void CodeGenerator::visit( CompoundLiteralExpr *compLitExpr ) { 661 assert( compLitExpr->get_type() && dynamic_cast< ListInit * > ( compLitExpr->get_initializer() ) ); 662 output << "(" << genType( compLitExpr->get_type(), "" ) << ")"; 663 compLitExpr->get_initializer()->accept( *this ); 664 } 665 666 void CodeGenerator::visit( StmtExpr * stmtExpr ) { 667 std::list< Statement * > & stmts = stmtExpr->get_statements()->get_kids(); 668 output << "({" << std::endl; 669 cur_indent += CodeGenerator::tabsize; 670 unsigned int numStmts = stmts.size(); 671 unsigned int i = 0; 672 for ( Statement * stmt : stmts ) { 673 output << indent << printLabels( stmt->get_labels() ); 674 if ( i+1 == numStmts ) { 675 // last statement in a statement expression needs to be handled specially - 676 // cannot cast to void, otherwise the expression statement has no value 677 if ( ExprStmt * exprStmt = dynamic_cast< ExprStmt * >( stmt ) ) { 678 exprStmt->get_expr()->accept( *this ); 679 output << ";" << endl; 680 ++i; 681 break; 682 } 683 } 684 stmt->accept( *this ); 685 output << endl; 686 if ( wantSpacing( stmt ) ) { 687 output << endl; 688 } // if 689 ++i; 690 } 691 cur_indent -= CodeGenerator::tabsize; 692 output << indent << "})"; 656 693 } 657 694 -
src/CodeGen/CodeGenerator.h
r3a2128f r1f44196 70 70 virtual void visit( ConditionalExpr *conditionalExpr ); 71 71 virtual void visit( CommaExpr *commaExpr ); 72 virtual void visit( CompoundLiteralExpr *compLitExpr ); 72 73 virtual void visit( TupleExpr *tupleExpr ); 73 74 virtual void visit( TypeExpr *typeExpr ); 74 75 virtual void visit( AsmExpr * ); 76 virtual void visit( StmtExpr * ); 75 77 76 78 //*** Statements -
src/CodeGen/GenType.cc
r3a2128f r1f44196 227 227 typeString = "_Atomic " + typeString; 228 228 } // if 229 if ( type->get_isAttribute() ) {230 typeString = "__attribute(( )) " + typeString;231 } // if232 229 } 233 230 } // namespace CodeGen -
src/Common/utility.h
r3a2128f r1f44196 148 148 } 149 149 150 // replace element of list with all elements of another list 150 151 template< typename T > 151 152 void replace( std::list< T > &org, typename std::list< T >::iterator pos, std::list< T > &with ) { … … 158 159 159 160 return; 161 } 162 163 // replace range of a list with a single element 164 template< typename T > 165 void replace( std::list< T > &org, typename std::list< T >::iterator begin, typename std::list< T >::iterator end, const T & with ) { 166 org.insert( begin, with ); 167 org.erase( begin, end ); 160 168 } 161 169 -
src/ControlStruct/Mutate.cc
r3a2128f r1f44196 23 23 #include "MLEMutator.h" 24 24 #include "ForExprMutator.h" 25 #include "LabelTypeChecker.h"26 25 //#include "ExceptMutator.h" 27 26 … … 41 40 42 41 //ExceptMutator exc; 43 // LabelTypeChecker lbl;44 42 45 43 mutateAll( translationUnit, formut ); 46 44 acceptAll( translationUnit, lfix ); 47 45 //mutateAll( translationUnit, exc ); 48 //acceptAll( translationUnit, lbl );49 46 } 50 47 } // namespace CodeGen -
src/ControlStruct/module.mk
r3a2128f r1f44196 6 6 ## file "LICENCE" distributed with Cforall. 7 7 ## 8 ## module.mk -- 8 ## module.mk -- 9 9 ## 10 10 ## Author : Richard C. Bilson … … 19 19 ControlStruct/MLEMutator.cc \ 20 20 ControlStruct/Mutate.cc \ 21 ControlStruct/ForExprMutator.cc \ 22 ControlStruct/LabelTypeChecker.cc 21 ControlStruct/ForExprMutator.cc 23 22 -
src/GenPoly/Box.cc
r3a2128f r1f44196 113 113 void addInferredParams( ApplicationExpr *appExpr, FunctionType *functionType, std::list< Expression *>::iterator &arg, const TyVarMap &tyVars ); 114 114 /// Stores assignment operators from assertion list in local map of assignment operations 115 void findTypeOps( const std::list< TypeDecl *>&forall );115 void findTypeOps( const Type::ForallList &forall ); 116 116 void passAdapters( ApplicationExpr *appExpr, FunctionType *functionType, const TyVarMap &exprTyVars ); 117 117 FunctionDecl *makeAdapter( FunctionType *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars ); … … 619 619 } 620 620 621 void Pass1::findTypeOps( const std::list< TypeDecl *>&forall ) {621 void Pass1::findTypeOps( const Type::ForallList &forall ) { 622 622 // what if a nested function uses an assignment operator? 623 623 // assignOps.clear(); 624 for ( std::list< TypeDecl *>::const_iterator i = forall.begin(); i != forall.end(); ++i ) {624 for ( Type::ForallList::const_iterator i = forall.begin(); i != forall.end(); ++i ) { 625 625 for ( std::list< DeclarationWithType *>::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) { 626 626 std::string typeName; … … 687 687 std::list< DeclarationWithType *> ¶mList = functionType->get_parameters(); 688 688 std::list< FunctionType *> functions; 689 for ( std::list< TypeDecl *>::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) {689 for ( Type::ForallList::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) { 690 690 for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->get_assertions().begin(); assert != (*tyVar)->get_assertions().end(); ++assert ) { 691 691 findFunction( (*assert)->get_type(), functions, scopeTyVars, needsAdapter ); … … 789 789 790 790 // add size/align for generic types to parameter list 791 if ( appExpr->get_function()->get_results().empty() ) return;792 FunctionType *funcType = getFunctionType( appExpr->get_function()->get_result s().front() );791 if ( ! appExpr->get_function()->has_result() ) return; 792 FunctionType *funcType = getFunctionType( appExpr->get_function()->get_result() ); 793 793 assert( funcType ); 794 794 … … 806 806 for ( ; fnParm != funcType->get_parameters().end() && fnArg != appExpr->get_args().end(); ++fnParm, ++fnArg ) { 807 807 VariableExpr *fnArgBase = getBaseVar( *fnArg ); 808 if ( ! fnArgBase || fnArgBase->get_results().empty() ) continue;809 passArgTypeVars( appExpr, (*fnParm)->get_type(), fnArgBase->get_result s().front(), arg, exprTyVars, seenTypes );808 if ( ! fnArgBase ) continue; // xxx - previously had check for non-empty fnArgBase results 809 passArgTypeVars( appExpr, (*fnParm)->get_type(), fnArgBase->get_result(), arg, exprTyVars, seenTypes ); 810 810 } 811 811 } … … 897 897 Type * adapteeType = new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) ); 898 898 appExpr->get_args().push_front( new CastExpr( appExpr->get_function(), adapteeType ) ); 899 appExpr->set_function( new NameExpr( adapterName ) ); 899 appExpr->set_function( new NameExpr( adapterName ) ); // xxx - result is never set on NameExpr 900 900 901 901 return ret; … … 903 903 904 904 void Pass1::boxParam( Type *param, Expression *&arg, const TyVarMap &exprTyVars ) { 905 assert( ! arg->get_results().empty() );905 assert( arg->has_result() ); 906 906 if ( isPolyType( param, exprTyVars ) ) { 907 if ( isPolyType( arg->get_result s().front() ) ) {907 if ( isPolyType( arg->get_result() ) ) { 908 908 // if the argument's type is polymorphic, we don't need to box again! 909 909 return; 910 } else if ( arg->get_result s().front()->get_isLvalue() ) {910 } else if ( arg->get_result()->get_isLvalue() ) { 911 911 // VariableExpr and MemberExpr are lvalues; need to check this isn't coming from the second arg of a comma expression though (not an lvalue) 912 912 // xxx - need to test that this code is still reachable … … 953 953 void Pass1::addInferredParams( ApplicationExpr *appExpr, FunctionType *functionType, std::list< Expression *>::iterator &arg, const TyVarMap &tyVars ) { 954 954 std::list< Expression *>::iterator cur = arg; 955 for ( std::list< TypeDecl *>::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) {955 for ( Type::ForallList::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) { 956 956 for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->get_assertions().begin(); assert != (*tyVar)->get_assertions().end(); ++assert ) { 957 957 InferredParams::const_iterator inferParam = appExpr->get_inferParams().find( (*assert)->get_uniqueId() ); … … 994 994 UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) ); 995 995 deref->get_args().push_back( new CastExpr( new VariableExpr( param ), new PointerType( Type::Qualifiers(), arg->get_type()->clone() ) ) ); 996 deref-> get_results().push_back( arg->get_type()->clone() );996 deref->set_result( arg->get_type()->clone() ); 997 997 return deref; 998 998 } // if … … 1020 1020 Statement *bodyStmt; 1021 1021 1022 std::list< TypeDecl *>::iterator tyArg = realType->get_forall().begin();1023 std::list< TypeDecl *>::iterator tyParam = adapterType->get_forall().begin();1024 std::list< TypeDecl *>::iterator realTyParam = adaptee->get_forall().begin();1022 Type::ForallList::iterator tyArg = realType->get_forall().begin(); 1023 Type::ForallList::iterator tyParam = adapterType->get_forall().begin(); 1024 Type::ForallList::iterator realTyParam = adaptee->get_forall().begin(); 1025 1025 for ( ; tyParam != adapterType->get_forall().end(); ++tyArg, ++tyParam, ++realTyParam ) { 1026 1026 assert( tyArg != realType->get_forall().end() ); … … 1071 1071 std::list< DeclarationWithType *> ¶mList = functionType->get_parameters(); 1072 1072 std::list< FunctionType *> functions; 1073 for ( std::list< TypeDecl *>::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) {1073 for ( Type::ForallList::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) { 1074 1074 for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->get_assertions().begin(); assert != (*tyVar)->get_assertions().end(); ++assert ) { 1075 1075 findFunction( (*assert)->get_type(), functions, exprTyVars, needsAdapter ); … … 1131 1131 } // if 1132 1132 addAssign->get_args().push_back( new NameExpr( sizeofName( mangleType( polyType ) ) ) ); 1133 addAssign-> get_results().front() = appExpr->get_results().front()->clone();1133 addAssign->set_result( appExpr->get_result()->clone() ); 1134 1134 if ( appExpr->get_env() ) { 1135 1135 addAssign->set_env( appExpr->get_env() ); … … 1145 1145 if ( varExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic ) { 1146 1146 if ( varExpr->get_var()->get_name() == "?[?]" ) { 1147 assert( ! appExpr->get_results().empty() );1147 assert( appExpr->has_result() ); 1148 1148 assert( appExpr->get_args().size() == 2 ); 1149 Type *baseType1 = isPolyPtr( appExpr->get_args().front()->get_result s().front(), scopeTyVars, env );1150 Type *baseType2 = isPolyPtr( appExpr->get_args().back()->get_result s().front(), scopeTyVars, env );1149 Type *baseType1 = isPolyPtr( appExpr->get_args().front()->get_result(), scopeTyVars, env ); 1150 Type *baseType2 = isPolyPtr( appExpr->get_args().back()->get_result(), scopeTyVars, env ); 1151 1151 assert( ! baseType1 || ! baseType2 ); // the arguments cannot both be polymorphic pointers 1152 1152 UntypedExpr *ret = 0; … … 1168 1168 } // if 1169 1169 if ( baseType1 || baseType2 ) { 1170 ret-> get_results().push_front( appExpr->get_results().front()->clone() );1170 ret->set_result( appExpr->get_result()->clone() ); 1171 1171 if ( appExpr->get_env() ) { 1172 1172 ret->set_env( appExpr->get_env() ); … … 1178 1178 } // if 1179 1179 } else if ( varExpr->get_var()->get_name() == "*?" ) { 1180 assert( ! appExpr->get_results().empty() );1180 assert( appExpr->has_result() ); 1181 1181 assert( ! appExpr->get_args().empty() ); 1182 if ( isPolyType( appExpr->get_result s().front(), scopeTyVars, env ) ) {1182 if ( isPolyType( appExpr->get_result(), scopeTyVars, env ) ) { 1183 1183 Expression *ret = appExpr->get_args().front(); 1184 delete ret->get_result s().front();1185 ret-> get_results().front() = appExpr->get_results().front()->clone();1184 delete ret->get_result(); 1185 ret->set_result( appExpr->get_result()->clone() ); 1186 1186 if ( appExpr->get_env() ) { 1187 1187 ret->set_env( appExpr->get_env() ); … … 1193 1193 } // if 1194 1194 } else if ( varExpr->get_var()->get_name() == "?++" || varExpr->get_var()->get_name() == "?--" ) { 1195 assert( ! appExpr->get_results().empty() );1195 assert( appExpr->has_result() ); 1196 1196 assert( appExpr->get_args().size() == 1 ); 1197 if ( Type *baseType = isPolyPtr( appExpr->get_result s().front(), scopeTyVars, env ) ) {1198 Type *tempType = appExpr->get_result s().front()->clone();1197 if ( Type *baseType = isPolyPtr( appExpr->get_result(), scopeTyVars, env ) ) { 1198 Type *tempType = appExpr->get_result()->clone(); 1199 1199 if ( env ) { 1200 1200 env->apply( tempType ); … … 1213 1213 } // if 1214 1214 } else if ( varExpr->get_var()->get_name() == "++?" || varExpr->get_var()->get_name() == "--?" ) { 1215 assert( ! appExpr->get_results().empty() );1215 assert( appExpr->has_result() ); 1216 1216 assert( appExpr->get_args().size() == 1 ); 1217 if ( Type *baseType = isPolyPtr( appExpr->get_result s().front(), scopeTyVars, env ) ) {1217 if ( Type *baseType = isPolyPtr( appExpr->get_result(), scopeTyVars, env ) ) { 1218 1218 return makeIncrDecrExpr( appExpr, baseType, varExpr->get_var()->get_name() == "++?" ); 1219 1219 } // if 1220 1220 } else if ( varExpr->get_var()->get_name() == "?+?" || varExpr->get_var()->get_name() == "?-?" ) { 1221 assert( ! appExpr->get_results().empty() );1221 assert( appExpr->has_result() ); 1222 1222 assert( appExpr->get_args().size() == 2 ); 1223 Type *baseType1 = isPolyPtr( appExpr->get_args().front()->get_result s().front(), scopeTyVars, env );1224 Type *baseType2 = isPolyPtr( appExpr->get_args().back()->get_result s().front(), scopeTyVars, env );1223 Type *baseType1 = isPolyPtr( appExpr->get_args().front()->get_result(), scopeTyVars, env ); 1224 Type *baseType2 = isPolyPtr( appExpr->get_args().back()->get_result(), scopeTyVars, env ); 1225 1225 if ( baseType1 && baseType2 ) { 1226 1226 UntypedExpr *divide = new UntypedExpr( new NameExpr( "?/?" ) ); 1227 1227 divide->get_args().push_back( appExpr ); 1228 1228 divide->get_args().push_back( new SizeofExpr( baseType1->clone() ) ); 1229 divide-> get_results().push_front( appExpr->get_results().front()->clone() );1229 divide->set_result( appExpr->get_result()->clone() ); 1230 1230 if ( appExpr->get_env() ) { 1231 1231 divide->set_env( appExpr->get_env() ); … … 1245 1245 } // if 1246 1246 } else if ( varExpr->get_var()->get_name() == "?+=?" || varExpr->get_var()->get_name() == "?-=?" ) { 1247 assert( ! appExpr->get_results().empty() );1247 assert( appExpr->has_result() ); 1248 1248 assert( appExpr->get_args().size() == 2 ); 1249 Type *baseType = isPolyPtr( appExpr->get_result s().front(), scopeTyVars, env );1249 Type *baseType = isPolyPtr( appExpr->get_result(), scopeTyVars, env ); 1250 1250 if ( baseType ) { 1251 1251 UntypedExpr *multiply = new UntypedExpr( new NameExpr( "?*?" ) ); … … 1273 1273 useRetval = oldUseRetval; 1274 1274 1275 assert( ! appExpr->get_function()->get_results().empty() ); 1276 PointerType *pointer = dynamic_cast< PointerType *>( appExpr->get_function()->get_results().front() ); 1277 assert( pointer ); 1278 FunctionType *function = dynamic_cast< FunctionType *>( pointer->get_base() ); 1279 assert( function ); 1275 assert( appExpr->get_function()->has_result() ); 1276 PointerType *pointer = safe_dynamic_cast< PointerType *>( appExpr->get_function()->get_result() ); 1277 FunctionType *function = safe_dynamic_cast< FunctionType *>( pointer->get_base() ); 1280 1278 1281 1279 if ( Expression *newExpr = handleIntrinsics( appExpr ) ) { … … 1315 1313 1316 1314 Expression *Pass1::mutate( UntypedExpr *expr ) { 1317 if ( ! expr->get_results().empty() && isPolyType( expr->get_results().front(), scopeTyVars, env ) ) {1315 if ( expr->has_result() && isPolyType( expr->get_result(), scopeTyVars, env ) ) { 1318 1316 if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->get_function() ) ) { 1319 1317 if ( name->get_name() == "*?" ) { … … 1329 1327 1330 1328 Expression *Pass1::mutate( AddressExpr *addrExpr ) { 1331 assert( ! addrExpr->get_arg()->get_results().empty() );1329 assert( addrExpr->get_arg()->has_result() && ! addrExpr->get_arg()->get_result()->isVoid() ); 1332 1330 1333 1331 bool needs = false; 1334 1332 if ( UntypedExpr *expr = dynamic_cast< UntypedExpr *>( addrExpr->get_arg() ) ) { 1335 if ( ! expr->get_results().empty() && isPolyType( expr->get_results().front(), scopeTyVars, env ) ) {1333 if ( expr->has_result() && isPolyType( expr->get_result(), scopeTyVars, env ) ) { 1336 1334 if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->get_function() ) ) { 1337 1335 if ( name->get_name() == "*?" ) { 1338 1336 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr->get_args().front() ) ) { 1339 assert( ! appExpr->get_function()->get_results().empty() ); 1340 PointerType *pointer = dynamic_cast< PointerType *>( appExpr->get_function()->get_results().front() ); 1341 assert( pointer ); 1342 FunctionType *function = dynamic_cast< FunctionType *>( pointer->get_base() ); 1343 assert( function ); 1337 assert( appExpr->get_function()->has_result() ); 1338 PointerType *pointer = safe_dynamic_cast< PointerType *>( appExpr->get_function()->get_result() ); 1339 FunctionType *function = safe_dynamic_cast< FunctionType *>( pointer->get_base() ); 1344 1340 needs = needsAdapter( function, scopeTyVars ); 1345 1341 } // if … … 1350 1346 // isPolyType check needs to happen before mutating addrExpr arg, so pull it forward 1351 1347 // out of the if condition. 1352 bool polytype = isPolyType( addrExpr->get_arg()->get_result s().front(), scopeTyVars, env );1348 bool polytype = isPolyType( addrExpr->get_arg()->get_result(), scopeTyVars, env ); 1353 1349 addrExpr->set_arg( mutateExpression( addrExpr->get_arg() ) ); 1354 1350 if ( polytype || needs ) { 1355 1351 Expression *ret = addrExpr->get_arg(); 1356 delete ret->get_result s().front();1357 ret-> get_results().front() = addrExpr->get_results().front()->clone();1352 delete ret->get_result(); 1353 ret->set_result( addrExpr->get_result()->clone() ); 1358 1354 addrExpr->set_arg( 0 ); 1359 1355 delete addrExpr; … … 1393 1389 Statement * Pass1::mutate( ReturnStmt *returnStmt ) { 1394 1390 if ( retval && returnStmt->get_expr() ) { 1395 assert( ! returnStmt->get_expr()->get_results().empty() );1391 assert( returnStmt->get_expr()->has_result() && ! returnStmt->get_expr()->get_result()->isVoid() ); 1396 1392 // ***** Code Removal ***** After introducing a temporary variable for all return expressions, the following code appears superfluous. 1397 1393 // if ( returnStmt->get_expr()->get_results().front()->get_isLvalue() ) { … … 1427 1423 // find each of its needed secondary assignment operators 1428 1424 std::list< Expression* > &tyParams = refType->get_parameters(); 1429 std::list< TypeDecl* >&forallParams = functionDecl->get_type()->get_forall();1425 Type::ForallList &forallParams = functionDecl->get_type()->get_forall(); 1430 1426 std::list< Expression* >::const_iterator tyIt = tyParams.begin(); 1431 std::list< TypeDecl* >::const_iterator forallIt = forallParams.begin();1427 Type::ForallList::const_iterator forallIt = forallParams.begin(); 1432 1428 for ( ; tyIt != tyParams.end() && forallIt != forallParams.end(); ++tyIt, ++forallIt ) { 1433 1429 // Add appropriate mapping to assignment expression environment … … 1473 1469 // replace return statement with appropriate assignment to out parameter 1474 1470 Expression *retParm = new NameExpr( retval->get_name() ); 1475 retParm-> get_results().push_back( new PointerType( Type::Qualifiers(), retval->get_type()->clone() ) );1471 retParm->set_result( new PointerType( Type::Qualifiers(), retval->get_type()->clone() ) ); 1476 1472 assignExpr->get_args().push_back( retParm ); 1477 1473 assignExpr->get_args().push_back( returnStmt->get_expr() ); … … 1603 1599 ObjectDecl newPtr( "", DeclarationNode::NoStorageClass, LinkageSpec::C, 0, 1604 1600 new PointerType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) ), 0 ); 1605 for ( std::list< TypeDecl *>::const_iterator tyParm = funcType->get_forall().begin(); tyParm != funcType->get_forall().end(); ++tyParm ) {1601 for ( Type::ForallList::const_iterator tyParm = funcType->get_forall().begin(); tyParm != funcType->get_forall().end(); ++tyParm ) { 1606 1602 ObjectDecl *sizeParm, *alignParm; 1607 1603 // add all size and alignment parameters to parameter list -
src/GenPoly/CopyParams.cc
r3a2128f r1f44196 54 54 std::map< std::string, DeclarationWithType* > assignOps; 55 55 // assume the assignment operator is the first assert param after any "type" parameter 56 for ( std::list< TypeDecl* >::const_iterator tyVar = funcDecl->get_functionType()->get_forall().begin(); tyVar != funcDecl->get_functionType()->get_forall().end(); ++tyVar ) {56 for ( Type::ForallList::const_iterator tyVar = funcDecl->get_functionType()->get_forall().begin(); tyVar != funcDecl->get_functionType()->get_forall().end(); ++tyVar ) { 57 57 if ( (*tyVar)->get_kind() == TypeDecl::Any ) { 58 58 assert( !(*tyVar)->get_assertions().empty() ); -
src/GenPoly/FindFunction.cc
r3a2128f r1f44196 29 29 virtual Type *mutate( PointerType *pointerType ); 30 30 private: 31 void handleForall( const std::list< TypeDecl* >&forall );31 void handleForall( const Type::ForallList &forall ); 32 32 33 33 std::list< FunctionType* > &functions; … … 51 51 } 52 52 53 void FindFunction::handleForall( const std::list< TypeDecl* >&forall ) {54 for ( std::list< TypeDecl* >::const_iterator i = forall.begin(); i != forall.end(); ++i ) {53 void FindFunction::handleForall( const Type::ForallList &forall ) { 54 for ( Type::ForallList::const_iterator i = forall.begin(); i != forall.end(); ++i ) { 55 55 TyVarMap::iterator var = tyVars.find( (*i)->get_name() ); 56 56 if ( var != tyVars.end() ) { -
src/GenPoly/GenPoly.cc
r3a2128f r1f44196 110 110 ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &forallTypes ) { 111 111 if ( function->get_returnVals().empty() ) return 0; 112 112 113 113 return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes ); 114 114 } … … 127 127 // } // if 128 128 if ( isDynRet( adaptee, tyVars ) ) return true; 129 129 130 130 for ( std::list< DeclarationWithType* >::const_iterator innerArg = adaptee->get_parameters().begin(); innerArg != adaptee->get_parameters().end(); ++innerArg ) { 131 131 // if ( isPolyType( (*innerArg)->get_type(), tyVars ) ) { … … 228 228 229 229 void makeTyVarMap( Type *type, TyVarMap &tyVarMap ) { 230 for ( std::list< TypeDecl* >::const_iterator tyVar = type->get_forall().begin(); tyVar != type->get_forall().end(); ++tyVar ) {230 for ( Type::ForallList::const_iterator tyVar = type->get_forall().begin(); tyVar != type->get_forall().end(); ++tyVar ) { 231 231 assert( *tyVar ); 232 232 tyVarMap[ (*tyVar)->get_name() ] = (*tyVar)->get_kind(); -
src/GenPoly/Lvalue.cc
r3a2128f r1f44196 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // Lvalue.cc -- 7 // Lvalue.cc -- 8 8 // 9 9 // Author : Richard C. Bilson … … 41 41 public: 42 42 Pass1(); 43 43 44 44 virtual Expression *mutate( ApplicationExpr *appExpr ); 45 45 virtual Statement *mutate( ReturnStmt *appExpr ); … … 55 55 private: 56 56 }; 57 58 /// GCC-like Generalized Lvalues (which have since been removed from GCC) 59 /// https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Lvalues.html#Lvalues 60 /// Replaces &(a,b) with (a, &b), &(a ? b : c) with (a ? &b : &c) 61 class GeneralizedLvalue : public Mutator { 62 typedef Mutator Parent; 63 64 virtual Expression * mutate( AddressExpr * addressExpr ); 65 }; 57 66 } // namespace 58 67 … … 60 69 Pass1 p1; 61 70 Pass2 p2; 71 GeneralizedLvalue genLval; 62 72 mutateAll( translationUnit, p1 ); 63 73 acceptAll( translationUnit, p2 ); 74 mutateAll( translationUnit, genLval ); 64 75 } 65 76 … … 99 110 appExpr->get_function()->acceptMutator( *this ); 100 111 mutateAll( appExpr->get_args(), *this ); 101 102 assert( ! appExpr->get_function()->get_results().empty() );103 112 104 PointerType *pointer = dynamic_cast< PointerType* >( appExpr->get_function()->get_results().front() ); 105 assert( pointer ); 106 FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ); 107 assert( function ); 113 PointerType *pointer = safe_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() ); 114 FunctionType *function = safe_dynamic_cast< FunctionType* >( pointer->get_base() ); 108 115 109 116 Type *funType = isLvalueRet( function ); 110 117 if ( funType && ! isIntrinsicApp( appExpr ) ) { 111 118 Expression *expr = appExpr; 112 Type *appType = appExpr->get_result s().front();119 Type *appType = appExpr->get_result(); 113 120 if ( isPolyType( funType ) && ! isPolyType( appType ) ) { 114 121 // make sure cast for polymorphic type is inside dereference … … 116 123 } 117 124 UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) ); 118 deref-> get_results().push_back( appType->clone() );119 appExpr-> get_results().front() = new PointerType( Type::Qualifiers(), appType);125 deref->set_result( appType->clone() ); 126 appExpr->set_result( new PointerType( Type::Qualifiers(), appType ) ); 120 127 deref->get_args().push_back( expr ); 121 128 return deref; … … 127 134 Statement * Pass1::mutate(ReturnStmt *retStmt) { 128 135 if ( retval && retStmt->get_expr() ) { 129 assert( ! retStmt->get_expr()->get_results().empty() ); 130 if ( retStmt->get_expr()->get_results().front()->get_isLvalue() ) { 136 if ( retStmt->get_expr()->get_result()->get_isLvalue() ) { 131 137 // ***** Code Removal ***** because casts may be stripped already 132 138 … … 155 161 retParm->set_type( new PointerType( Type::Qualifiers(), retParm->get_type() ) ); 156 162 } // if 157 163 158 164 Visitor::visit( funType ); 165 } 166 167 Expression * GeneralizedLvalue::mutate( AddressExpr * addrExpr ) { 168 addrExpr = safe_dynamic_cast< AddressExpr * >( Parent::mutate( addrExpr ) ); 169 if ( CommaExpr * commaExpr = dynamic_cast< CommaExpr * >( addrExpr->get_arg() ) ) { 170 Expression * arg1 = commaExpr->get_arg1()->clone(); 171 Expression * arg2 = commaExpr->get_arg2()->clone(); 172 delete addrExpr; 173 return new CommaExpr( arg1, new AddressExpr( arg2 ) ); 174 } else if ( ConditionalExpr * condExpr = dynamic_cast< ConditionalExpr * >( addrExpr->get_arg() ) ) { 175 Expression * arg1 = condExpr->get_arg1()->clone(); 176 Expression * arg2 = condExpr->get_arg2()->clone(); 177 Expression * arg3 = condExpr->get_arg3()->clone(); 178 delete addrExpr; 179 return new ConditionalExpr( arg1, new AddressExpr( arg2 ), new AddressExpr( arg3 ) ); 180 } 181 return addrExpr; 159 182 } 160 183 } // namespace -
src/GenPoly/Specialize.cc
r3a2128f r1f44196 148 148 149 149 Expression * Specialize::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) { 150 assert ( ! actual->get_results().empty() ); // using front, should have this assert151 if ( needsSpecialization( formalType, actual->get_result s().front(), env ) ) {150 assertf( actual->has_result(), "attempting to specialize an untyped expression" ); 151 if ( needsSpecialization( formalType, actual->get_result(), env ) ) { 152 152 FunctionType *funType; 153 153 if ( ( funType = getFunctionType( formalType ) ) ) { … … 172 172 void Specialize::handleExplicitParams( ApplicationExpr *appExpr ) { 173 173 // create thunks for the explicit parameters 174 assert( ! appExpr->get_function()->get_results().empty() );175 FunctionType *function = getFunctionType( appExpr->get_function()->get_result s().front() );174 assert( appExpr->get_function()->has_result() ); 175 FunctionType *function = getFunctionType( appExpr->get_function()->get_result() ); 176 176 assert( function ); 177 177 std::list< DeclarationWithType* >::iterator formal; … … 201 201 Expression * Specialize::mutate( AddressExpr *addrExpr ) { 202 202 addrExpr->get_arg()->acceptMutator( *this ); 203 assert( ! addrExpr->get_results().empty() );204 addrExpr->set_arg( doSpecialization( addrExpr->get_result s().front(), addrExpr->get_arg() ) );203 assert( addrExpr->has_result() ); 204 addrExpr->set_arg( doSpecialization( addrExpr->get_result(), addrExpr->get_arg() ) ); 205 205 return addrExpr; 206 206 } … … 208 208 Expression * Specialize::mutate( CastExpr *castExpr ) { 209 209 castExpr->get_arg()->acceptMutator( *this ); 210 if ( castExpr->get_result s().empty() ) {210 if ( castExpr->get_result()->isVoid() ) { 211 211 // can't specialize if we don't have a return value 212 212 return castExpr; 213 213 } 214 Expression *specialized = doSpecialization( castExpr->get_result s().front(), castExpr->get_arg() );214 Expression *specialized = doSpecialization( castExpr->get_result(), castExpr->get_arg() ); 215 215 if ( specialized != castExpr->get_arg() ) { 216 216 // assume here that the specialization incorporates the cast -
src/InitTweak/FixInit.cc
r3a2128f r1f44196 18 18 #include <iterator> 19 19 #include <algorithm> 20 #include <unordered_map> 21 #include <unordered_set> 20 22 #include "InitTweak.h" 21 23 #include "FixInit.h" … … 35 37 #include "GenPoly/DeclMutator.h" 36 38 #include "SynTree/AddStmtVisitor.h" 37 #include "CodeGen/GenType.h" // for warning s38 39 bool ctordtorp = false; 40 bool ctorp = false; 41 bool cpctorp = false; 42 bool dtorp = false; 39 #include "CodeGen/GenType.h" // for warning/error messages 40 41 bool ctordtorp = false; // print all debug 42 bool ctorp = false; // print ctor debug 43 bool cpctorp = false; // print copy ctor debug 44 bool dtorp = false; // print dtor debug 43 45 #define PRINT( text ) if ( ctordtorp ) { text } 44 46 #define CP_CTOR_PRINT( text ) if ( ctordtorp || cpctorp ) { text } … … 47 49 namespace InitTweak { 48 50 namespace { 49 const std::list<Label> noLabels;50 const std::list<Expression*> noDesignators;51 52 51 class InsertImplicitCalls final : public GenPoly::PolyMutator { 53 52 public: … … 67 66 static void resolveImplicitCalls( std::list< Declaration * > & translationUnit ); 68 67 69 using SymTab::Indexer::visit; 68 typedef SymTab::Indexer Parent; 69 using Parent::visit; 70 70 71 virtual void visit( ImplicitCopyCtorExpr * impCpCtorExpr ) override; 72 virtual void visit( UniqueExpr * unqExpr ); 71 73 72 74 /// create and resolve ctor/dtor expression: fname(var, [cpArg]) 73 ApplicationExpr * makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg = NULL ); 75 Expression * makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg = NULL ); 76 Expression * makeCtorDtor( const std::string & fname, Expression * thisArg, Expression * cpArg = NULL ); 74 77 /// true if type does not need to be copy constructed to ensure correctness 75 bool skipCopyConstruct( Type * ); 78 bool skipCopyConstruct( Type * type ); 79 void copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr ); 80 void destructRet( Expression * ret, ImplicitCopyCtorExpr * impCpCtorExpr ); 76 81 private: 77 82 TypeSubstitution * env; … … 183 188 using GenPoly::PolyMutator::mutate; 184 189 virtual Expression * mutate( ImplicitCopyCtorExpr * impCpCtorExpr ) override; 190 virtual Expression * mutate( UniqueExpr * unqExpr ) override; 185 191 }; 186 192 … … 368 374 } 369 375 370 ApplicationExpr* ResolveCopyCtors::makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg ) {376 Expression * ResolveCopyCtors::makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg ) { 371 377 assert( var ); 378 return makeCtorDtor( fname, new AddressExpr( new VariableExpr( var ) ), cpArg ); 379 } 380 381 Expression * ResolveCopyCtors::makeCtorDtor( const std::string & fname, Expression * thisArg, Expression * cpArg ) { 382 assert( thisArg ); 372 383 UntypedExpr * untyped = new UntypedExpr( new NameExpr( fname ) ); 373 untyped->get_args().push_back( new AddressExpr( new VariableExpr( var ) ));384 untyped->get_args().push_back( thisArg ); 374 385 if (cpArg) untyped->get_args().push_back( cpArg->clone() ); 375 386 … … 378 389 // (VariableExpr and already resolved expression) 379 390 CP_CTOR_PRINT( std::cerr << "ResolvingCtorDtor " << untyped << std::endl; ) 380 ApplicationExpr * resolved = dynamic_cast< ApplicationExpr * >( ResolvExpr::findVoidExpression( untyped, *this ) ); 391 Expression * resolved = ResolvExpr::findVoidExpression( untyped, *this ); 392 assert( resolved ); 381 393 if ( resolved->get_env() ) { 382 394 env->add( *resolved->get_env() ); 383 395 } // if 384 396 385 assert( resolved );386 397 delete untyped; 387 398 return resolved; 388 399 } 389 400 401 void ResolveCopyCtors::copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr ) { 402 static UniqueName tempNamer("_tmp_cp"); 403 CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *impCpCtorExpr->get_env() << std::endl; ) 404 assert( arg->has_result() ); 405 Type * result = arg->get_result(); 406 if ( skipCopyConstruct( result ) ) return; // skip certain non-copyable types 407 408 // type may involve type variables, so apply type substitution to get temporary variable's actual type 409 result = result->clone(); 410 impCpCtorExpr->get_env()->apply( result ); 411 ObjectDecl * tmp = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 ); 412 tmp->get_type()->set_isConst( false ); 413 414 // create and resolve copy constructor 415 CP_CTOR_PRINT( std::cerr << "makeCtorDtor for an argument" << std::endl; ) 416 Expression * cpCtor = makeCtorDtor( "?{}", tmp, arg ); 417 418 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( cpCtor ) ) { 419 // if the chosen constructor is intrinsic, the copy is unnecessary, so 420 // don't create the temporary and don't call the copy constructor 421 VariableExpr * function = dynamic_cast< VariableExpr * >( appExpr->get_function() ); 422 assert( function ); 423 if ( function->get_var()->get_linkage() == LinkageSpec::Intrinsic ) return; 424 } 425 426 // replace argument to function call with temporary 427 arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) ); 428 impCpCtorExpr->get_tempDecls().push_back( tmp ); 429 impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", tmp ) ); 430 } 431 432 void ResolveCopyCtors::destructRet( Expression * ret, ImplicitCopyCtorExpr * impCpCtorExpr ) { 433 impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", new AddressExpr( ret ) ) ); 434 } 435 390 436 void ResolveCopyCtors::visit( ImplicitCopyCtorExpr *impCpCtorExpr ) { 391 static UniqueName tempNamer("_tmp_cp");392 static UniqueName retNamer("_tmp_cp_ret");393 394 437 CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; ) 395 Visitor::visit( impCpCtorExpr );438 Parent::visit( impCpCtorExpr ); 396 439 env = impCpCtorExpr->get_env(); // xxx - maybe we really should just have a PolyIndexer... 397 440 … … 400 443 // take each argument and attempt to copy construct it. 401 444 for ( Expression * & arg : appExpr->get_args() ) { 402 CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *impCpCtorExpr->get_env() << std::endl; ) 403 // xxx - need to handle tuple arguments 404 assert( ! arg->get_results().empty() ); 405 Type * result = arg->get_results().front(); 406 if ( skipCopyConstruct( result ) ) continue; // skip certain non-copyable types 407 // type may involve type variables, so apply type substitution to get temporary variable's actual type 408 result = result->clone(); 409 impCpCtorExpr->get_env()->apply( result ); 410 ObjectDecl * tmp = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 ); 411 tmp->get_type()->set_isConst( false ); 412 413 // create and resolve copy constructor 414 CP_CTOR_PRINT( std::cerr << "makeCtorDtor for an argument" << std::endl; ) 415 ApplicationExpr * cpCtor = makeCtorDtor( "?{}", tmp, arg ); 416 417 // if the chosen constructor is intrinsic, the copy is unnecessary, so 418 // don't create the temporary and don't call the copy constructor 419 VariableExpr * function = dynamic_cast< VariableExpr * >( cpCtor->get_function() ); 420 assert( function ); 421 if ( function->get_var()->get_linkage() != LinkageSpec::Intrinsic ) { 422 // replace argument to function call with temporary 423 arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) ); 424 impCpCtorExpr->get_tempDecls().push_back( tmp ); 425 impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", tmp ) ); 426 } // if 445 copyConstructArg( arg, impCpCtorExpr ); 427 446 } // for 428 447 … … 434 453 // level. Trying to pass that environment along. 435 454 callExpr->set_env( impCpCtorExpr->get_env()->clone() ); 436 for ( Type * result : appExpr->get_results() ) { 455 Type * result = appExpr->get_result(); 456 if ( ! result->isVoid() ) { 457 static UniqueName retNamer("_tmp_cp_ret"); 437 458 result = result->clone(); 438 459 impCpCtorExpr->get_env()->apply( result ); … … 441 462 impCpCtorExpr->get_returnDecls().push_back( ret ); 442 463 CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; ) 443 impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) ); 464 if ( ! result->get_isLvalue() ) { 465 // destructing lvalue returns is bad because it can cause multiple destructor calls to the same object - the returned object is not a temporary 466 destructRet( new VariableExpr( ret ), impCpCtorExpr ); 467 } 444 468 } // for 445 469 CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; ) 470 } 471 472 void ResolveCopyCtors::visit( UniqueExpr * unqExpr ) { 473 static std::unordered_set< int > vars; 474 if ( vars.count( unqExpr->get_id() ) ) { 475 // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated 476 return; 477 } 478 479 Parent::visit( unqExpr ); 480 // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought 481 assert( unqExpr->get_result() ); 482 if ( ImplicitCopyCtorExpr * impCpCtorExpr = dynamic_cast<ImplicitCopyCtorExpr*>( unqExpr->get_expr() ) ) { 483 // note the variable used as the result from the call 484 assert( impCpCtorExpr->get_result() && impCpCtorExpr->get_returnDecls().size() == 1 ); 485 unqExpr->set_var( new VariableExpr( impCpCtorExpr->get_returnDecls().front() ) ); 486 } else { 487 // expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression 488 unqExpr->set_object( new ObjectDecl( toString("_unq_expr_", unqExpr->get_id()), DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, unqExpr->get_result()->clone(), nullptr ) ); 489 unqExpr->set_var( new VariableExpr( unqExpr->get_object() ) ); 490 } 491 vars.insert( unqExpr->get_id() ); 446 492 } 447 493 … … 490 536 // know the result type of the assignment is the type of the LHS (minus the pointer), so 491 537 // add that onto the assignment expression so that later steps have the necessary information 492 assign-> add_result( returnDecl->get_type()->clone() );538 assign->set_result( returnDecl->get_type()->clone() ); 493 539 494 540 Expression * retExpr = new CommaExpr( assign, new VariableExpr( returnDecl ) ); 495 if ( callExpr->get_result s().front()->get_isLvalue() ) {541 if ( callExpr->get_result()->get_isLvalue() ) { 496 542 // lvalue returning functions are funny. Lvalue.cc inserts a *? in front of any lvalue returning 497 543 // non-intrinsic function. Add an AddressExpr to the call to negate the derefence and change the … … 500 546 // an AddressExpr. Effectively, this turns 501 547 // lvalue T f(); 502 // &*f() 548 // &*f(); 503 549 // into 550 // T * f(); 504 551 // T * tmp_cp_retN; 505 // tmp_cp_ret_N = &*(tmp_cp_ret_N = &*f(), tmp_cp_ret);552 // &*(tmp_cp_retN = &*f(), tmp_cp_retN); // the first * and second & are generated here 506 553 // which work out in terms of types, but is pretty messy. It would be nice to find a better way. 507 554 assign->get_args().back() = new AddressExpr( assign->get_args().back() ); 508 555 509 Type * resultType = returnDecl->get_type()->clone();510 556 returnDecl->set_type( new PointerType( Type::Qualifiers(), returnDecl->get_type() ) ); 511 UntypedExpr * deref = new UntypedExpr( new NameExpr( "*?" ) ); 512 deref->get_args().push_back( retExpr ); 513 deref->add_result( resultType ); 514 retExpr = deref; 557 retExpr->set_result( new PointerType( Type::Qualifiers(), retExpr->get_result() ) ); 558 retExpr = UntypedExpr::createDeref( retExpr ); 515 559 } // if 516 560 retExpr->set_env( env->clone() ); … … 519 563 return callExpr; 520 564 } // if 565 } 566 567 Expression * FixCopyCtors::mutate( UniqueExpr * unqExpr ) { 568 static std::unordered_map< int, UniqueExpr * > unqMap; 569 static std::unordered_set< int > addDeref; 570 // has to be done to clean up ImplicitCopyCtorExpr nodes, even when this node was skipped in previous passes 571 unqExpr = safe_dynamic_cast< UniqueExpr * >( Parent::mutate( unqExpr ) ); 572 if ( unqMap.count( unqExpr->get_id() ) ) { 573 // take data from other UniqueExpr to ensure consistency 574 delete unqExpr->get_expr(); 575 unqExpr->set_expr( unqMap[unqExpr->get_id()]->get_expr()->clone() ); 576 delete unqExpr->get_result(); 577 unqExpr->set_result( maybeClone( unqExpr->get_expr()->get_result() ) ); 578 if ( addDeref.count( unqExpr->get_id() ) ) { 579 // other UniqueExpr was dereferenced because it was an lvalue return, so this one should be too 580 return UntypedExpr::createDeref( unqExpr ); 581 } 582 return unqExpr; 583 } 584 unqMap[unqExpr->get_id()] = unqExpr; 585 if ( UntypedExpr * deref = dynamic_cast< UntypedExpr * >( unqExpr->get_expr() ) ) { 586 // unique expression is now a dereference, because the inner expression is an lvalue returning function call. 587 // Normalize the expression by dereferencing the unique expression, rather than the inner expression 588 // (i.e. move the dereference out a level) 589 assert( getFunctionName( deref ) == "*?" ); 590 unqExpr->set_expr( getCallArg( deref, 0 ) ); 591 getCallArg( deref, 0 ) = unqExpr; 592 addDeref.insert( unqExpr->get_id() ); 593 return deref; 594 } 595 return unqExpr; 521 596 } 522 597 … … 950 1025 Expression * FixCtorExprs::mutate( ConstructorExpr * ctorExpr ) { 951 1026 static UniqueName tempNamer( "_tmp_ctor_expr" ); 952 assert( ctorExpr->get_results().size() == 1 ); 953 ObjectDecl * tmp = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, ctorExpr->get_results().front()->clone(), nullptr ); 1027 // xxx - is the size check necessary? 1028 assert( ctorExpr->has_result() && ctorExpr->get_result()->size() == 1 ); 1029 ObjectDecl * tmp = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, ctorExpr->get_result()->clone(), nullptr ); 954 1030 addDeclaration( tmp ); 955 1031 … … 963 1039 assign->get_args().push_back( new VariableExpr( tmp ) ); 964 1040 assign->get_args().push_back( firstArg ); 965 cloneAll( ctorExpr->get_results(), assign->get_results() );1041 assign->set_result( ctorExpr->get_result()->clone() ); 966 1042 firstArg = assign; 967 1043 -
src/InitTweak/GenInit.cc
r3a2128f r1f44196 29 29 #include "GenPoly/DeclMutator.h" 30 30 #include "GenPoly/ScopedSet.h" 31 #include "ResolvExpr/typeops.h" 31 32 32 33 namespace InitTweak { … … 50 51 51 52 protected: 52 std::list<DeclarationWithType*> returnVals;53 FunctionType * ftype; 53 54 UniqueName tempNamer; 54 55 std::string funcName; … … 86 87 87 88 bool isManaged( ObjectDecl * objDecl ) const ; // determine if object is managed 89 bool isManaged( Type * type ) const; // determine if type is managed 88 90 void handleDWT( DeclarationWithType * dwt ); // add type to managed if ctor/dtor 89 91 GenPoly::ScopedSet< std::string > managedTypes; … … 136 138 137 139 Statement *ReturnFixer::mutate( ReturnStmt *returnStmt ) { 138 // update for multiple return values140 std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals(); 139 141 assert( returnVals.size() == 0 || returnVals.size() == 1 ); 140 142 // hands off if the function returns an lvalue - we don't want to allocate a temporary if a variable's address … … 158 160 159 161 DeclarationWithType* ReturnFixer::mutate( FunctionDecl *functionDecl ) { 160 ValueGuard< std::list<DeclarationWithType*> > oldReturnVals( returnVals ); 162 // xxx - need to handle named return values - this pass may need to happen 163 // after resolution? the ordering is tricky because return statements must be 164 // constructed - the simplest way to do that (while also handling multiple 165 // returns) is to structure the returnVals into a tuple, as done here. 166 // however, if the tuple return value is structured before resolution, 167 // it's difficult to resolve named return values, since the name is lost 168 // in conversion to a tuple. this might be easiest to deal with 169 // after reference types are added, as it may then be possible to 170 // uniformly move named return values to the parameter list directly 171 ValueGuard< FunctionType * > oldFtype( ftype ); 161 172 ValueGuard< std::string > oldFuncName( funcName ); 162 173 163 FunctionType * type = functionDecl->get_functionType(); 164 returnVals = type->get_returnVals(); 174 ftype = functionDecl->get_functionType(); 175 std::list< DeclarationWithType * > & retVals = ftype->get_returnVals(); 176 if ( retVals.size() > 1 ) { 177 TupleType * tupleType = safe_dynamic_cast< TupleType * >( ResolvExpr::extractResultType( ftype ) ); 178 ObjectDecl * newRet = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, tupleType, new ListInit( std::list<Initializer*>(), noDesignators, false ) ); 179 retVals.clear(); 180 retVals.push_back( newRet ); 181 } 165 182 funcName = functionDecl->get_name(); 166 183 DeclarationWithType * decl = Mutator::mutate( functionDecl ); … … 222 239 } 223 240 241 bool CtorDtor::isManaged( Type * type ) const { 242 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( type ) ) { 243 // tuple is also managed if any of its components are managed 244 if ( std::any_of( tupleType->get_types().begin(), tupleType->get_types().end(), [&](Type * type) { return isManaged( type ); }) ) { 245 return true; 246 } 247 } 248 return managedTypes.find( SymTab::Mangler::mangle( type ) ) != managedTypes.end(); 249 } 250 224 251 bool CtorDtor::isManaged( ObjectDecl * objDecl ) const { 225 252 Type * type = objDecl->get_type(); … … 227 254 type = at->get_base(); 228 255 } 229 return managedTypes.find( SymTab::Mangler::mangle( type ) ) != managedTypes.end();256 return isManaged( type ); 230 257 } 231 258 … … 238 265 managedTypes.insert( SymTab::Mangler::mangle( type->get_base() ) ); 239 266 } 267 } 268 269 ConstructorInit * genCtorInit( ObjectDecl * objDecl ) { 270 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor 271 // for each constructable object 272 std::list< Statement * > ctor; 273 std::list< Statement * > dtor; 274 275 InitExpander srcParam( objDecl->get_init() ); 276 InitExpander nullParam( (Initializer *)NULL ); 277 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl ); 278 SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false ); 279 280 // Currently genImplicitCall produces a single Statement - a CompoundStmt 281 // which wraps everything that needs to happen. As such, it's technically 282 // possible to use a Statement ** in the above calls, but this is inherently 283 // unsafe, so instead we take the slightly less efficient route, but will be 284 // immediately informed if somehow the above assumption is broken. In this case, 285 // we could always wrap the list of statements at this point with a CompoundStmt, 286 // but it seems reasonable at the moment for this to be done by genImplicitCall 287 // itself. It is possible that genImplicitCall produces no statements (e.g. if 288 // an array type does not have a dimension). In this case, it's fine to ignore 289 // the object for the purposes of construction. 290 assert( ctor.size() == dtor.size() && ctor.size() <= 1 ); 291 if ( ctor.size() == 1 ) { 292 // need to remember init expression, in case no ctors exist 293 // if ctor does exist, want to use ctor expression instead of init 294 // push this decision to the resolver 295 assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) ); 296 return new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ); 297 } 298 return nullptr; 240 299 } 241 300 … … 250 309 if ( ! checkInitDepth( objDecl ) ) throw SemanticError( "Managed object's initializer is too deep ", objDecl ); 251 310 252 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor 253 // for each constructable object 254 std::list< Statement * > ctor; 255 std::list< Statement * > dtor; 256 257 InitExpander srcParam( objDecl->get_init() ); 258 InitExpander nullParam( (Initializer *)NULL ); 259 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl ); 260 SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false ); 261 262 // Currently genImplicitCall produces a single Statement - a CompoundStmt 263 // which wraps everything that needs to happen. As such, it's technically 264 // possible to use a Statement ** in the above calls, but this is inherently 265 // unsafe, so instead we take the slightly less efficient route, but will be 266 // immediately informed if somehow the above assumption is broken. In this case, 267 // we could always wrap the list of statements at this point with a CompoundStmt, 268 // but it seems reasonable at the moment for this to be done by genImplicitCall 269 // itself. It is possible that genImplicitCall produces no statements (e.g. if 270 // an array type does not have a dimension). In this case, it's fine to ignore 271 // the object for the purposes of construction. 272 assert( ctor.size() == dtor.size() && ctor.size() <= 1 ); 273 if ( ctor.size() == 1 ) { 274 // need to remember init expression, in case no ctors exist 275 // if ctor does exist, want to use ctor expression instead of init 276 // push this decision to the resolver 277 assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) ); 278 objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) ); 279 } 311 objDecl->set_init( genCtorInit( objDecl ) ); 280 312 } 281 313 return Parent::mutate( objDecl ); … … 290 322 managedTypes.beginScope(); 291 323 // go through assertions and recursively add seen ctor/dtors 292 for ( TypeDecl *tyDecl : functionDecl->get_functionType()->get_forall() ) {324 for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) { 293 325 for ( DeclarationWithType *& assertion : tyDecl->get_assertions() ) { 294 326 assertion = assertion->acceptMutator( *this ); -
src/InitTweak/GenInit.h
r3a2128f r1f44196 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // RemoveInit.h --7 // GenInit.h -- 8 8 // 9 9 // Author : Rodolfo G. Esteves … … 27 27 /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes 28 28 void genInit( std::list< Declaration * > & translationUnit ); 29 30 /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer 31 ConstructorInit * genCtorInit( ObjectDecl * objDecl ); 29 32 } // namespace 30 33 -
src/InitTweak/InitTweak.cc
r3a2128f r1f44196 340 340 return allofCtorDtor( stmt, []( Expression * callExpr ){ 341 341 if ( ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) { 342 assert( ! appExpr->get_function()->get_results().empty() ); 343 FunctionType *funcType = GenPoly::getFunctionType( appExpr->get_function()->get_results().front() ); 342 FunctionType *funcType = GenPoly::getFunctionType( appExpr->get_function()->get_result() ); 344 343 assert( funcType ); 345 344 return funcType->get_parameters().size() == 1; … … 388 387 return memberExpr->get_member()->get_name(); 389 388 } else if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * > ( func ) ) { 390 return memberExpr->get_member();389 return funcName( memberExpr->get_member() ); 391 390 } else { 392 391 assertf( false, "Unexpected expression type being called as a function in call expression" ); … … 451 450 // virtual void visit( LogicalExpr *logicalExpr ); 452 451 // virtual void visit( ConditionalExpr *conditionalExpr ); 453 virtual void visit( TupleExpr *tupleExpr ) { isConstExpr = false; }454 virtual void visit( SolvedTupleExpr *tupleExpr ) { isConstExpr = false; }455 452 virtual void visit( TypeExpr *typeExpr ) { isConstExpr = false; } 456 453 virtual void visit( AsmExpr *asmExpr ) { isConstExpr = false; } 457 454 virtual void visit( UntypedValofExpr *valofExpr ) { isConstExpr = false; } 458 455 virtual void visit( CompoundLiteralExpr *compLitExpr ) { isConstExpr = false; } 456 virtual void visit( TupleExpr *tupleExpr ) { isConstExpr = false; } 457 virtual void visit( TupleAssignExpr *tupleExpr ) { isConstExpr = false; } 459 458 460 459 bool isConstExpr; -
src/Makefile.in
r3a2128f r1f44196 105 105 ControlStruct/driver_cfa_cpp-Mutate.$(OBJEXT) \ 106 106 ControlStruct/driver_cfa_cpp-ForExprMutator.$(OBJEXT) \ 107 ControlStruct/driver_cfa_cpp-LabelTypeChecker.$(OBJEXT) \108 107 GenPoly/driver_cfa_cpp-Box.$(OBJEXT) \ 109 108 GenPoly/driver_cfa_cpp-GenPoly.$(OBJEXT) \ … … 190 189 SynTree/driver_cfa_cpp-TypeSubstitution.$(OBJEXT) \ 191 190 SynTree/driver_cfa_cpp-Attribute.$(OBJEXT) \ 191 SynTree/driver_cfa_cpp-VarExprReplacer.$(OBJEXT) \ 192 192 Tuples/driver_cfa_cpp-TupleAssignment.$(OBJEXT) \ 193 Tuples/driver_cfa_cpp-NameMatcher.$(OBJEXT) 193 Tuples/driver_cfa_cpp-TupleExpansion.$(OBJEXT) \ 194 Tuples/driver_cfa_cpp-Explode.$(OBJEXT) 194 195 am_driver_cfa_cpp_OBJECTS = $(am__objects_1) 195 196 driver_cfa_cpp_OBJECTS = $(am_driver_cfa_cpp_OBJECTS) … … 364 365 ControlStruct/LabelGenerator.cc ControlStruct/LabelFixer.cc \ 365 366 ControlStruct/MLEMutator.cc ControlStruct/Mutate.cc \ 366 ControlStruct/ForExprMutator.cc \ 367 ControlStruct/LabelTypeChecker.cc GenPoly/Box.cc \ 367 ControlStruct/ForExprMutator.cc GenPoly/Box.cc \ 368 368 GenPoly/GenPoly.cc GenPoly/PolyMutator.cc \ 369 369 GenPoly/ScrubTyVars.cc GenPoly/Lvalue.cc GenPoly/Specialize.cc \ … … 404 404 SynTree/Initializer.cc SynTree/Visitor.cc SynTree/Mutator.cc \ 405 405 SynTree/AddStmtVisitor.cc SynTree/TypeSubstitution.cc \ 406 SynTree/Attribute.cc Tuples/TupleAssignment.cc \ 407 Tuples/NameMatcher.cc 406 SynTree/Attribute.cc SynTree/VarExprReplacer.cc \ 407 Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc \ 408 Tuples/Explode.cc 408 409 MAINTAINERCLEANFILES = Parser/parser.output ${libdir}/${notdir \ 409 410 ${cfa_cpplib_PROGRAMS}} … … 541 542 ControlStruct/$(DEPDIR)/$(am__dirstamp) 542 543 ControlStruct/driver_cfa_cpp-ForExprMutator.$(OBJEXT): \ 543 ControlStruct/$(am__dirstamp) \544 ControlStruct/$(DEPDIR)/$(am__dirstamp)545 ControlStruct/driver_cfa_cpp-LabelTypeChecker.$(OBJEXT): \546 544 ControlStruct/$(am__dirstamp) \ 547 545 ControlStruct/$(DEPDIR)/$(am__dirstamp) … … 769 767 SynTree/driver_cfa_cpp-Attribute.$(OBJEXT): SynTree/$(am__dirstamp) \ 770 768 SynTree/$(DEPDIR)/$(am__dirstamp) 769 SynTree/driver_cfa_cpp-VarExprReplacer.$(OBJEXT): \ 770 SynTree/$(am__dirstamp) SynTree/$(DEPDIR)/$(am__dirstamp) 771 771 Tuples/$(am__dirstamp): 772 772 @$(MKDIR_P) Tuples … … 777 777 Tuples/driver_cfa_cpp-TupleAssignment.$(OBJEXT): \ 778 778 Tuples/$(am__dirstamp) Tuples/$(DEPDIR)/$(am__dirstamp) 779 Tuples/driver_cfa_cpp-NameMatcher.$(OBJEXT): Tuples/$(am__dirstamp) \ 779 Tuples/driver_cfa_cpp-TupleExpansion.$(OBJEXT): \ 780 Tuples/$(am__dirstamp) Tuples/$(DEPDIR)/$(am__dirstamp) 781 Tuples/driver_cfa_cpp-Explode.$(OBJEXT): Tuples/$(am__dirstamp) \ 780 782 Tuples/$(DEPDIR)/$(am__dirstamp) 781 783 driver/$(am__dirstamp): … … 800 802 -rm -f ControlStruct/driver_cfa_cpp-LabelFixer.$(OBJEXT) 801 803 -rm -f ControlStruct/driver_cfa_cpp-LabelGenerator.$(OBJEXT) 802 -rm -f ControlStruct/driver_cfa_cpp-LabelTypeChecker.$(OBJEXT)803 804 -rm -f ControlStruct/driver_cfa_cpp-MLEMutator.$(OBJEXT) 804 805 -rm -f ControlStruct/driver_cfa_cpp-Mutate.$(OBJEXT) … … 884 885 -rm -f SynTree/driver_cfa_cpp-TypeofType.$(OBJEXT) 885 886 -rm -f SynTree/driver_cfa_cpp-VarArgsType.$(OBJEXT) 887 -rm -f SynTree/driver_cfa_cpp-VarExprReplacer.$(OBJEXT) 886 888 -rm -f SynTree/driver_cfa_cpp-Visitor.$(OBJEXT) 887 889 -rm -f SynTree/driver_cfa_cpp-VoidType.$(OBJEXT) 888 890 -rm -f SynTree/driver_cfa_cpp-ZeroOneType.$(OBJEXT) 889 -rm -f Tuples/driver_cfa_cpp- NameMatcher.$(OBJEXT)891 -rm -f Tuples/driver_cfa_cpp-Explode.$(OBJEXT) 890 892 -rm -f Tuples/driver_cfa_cpp-TupleAssignment.$(OBJEXT) 893 -rm -f Tuples/driver_cfa_cpp-TupleExpansion.$(OBJEXT) 891 894 892 895 distclean-compile: … … 907 910 @AMDEP_TRUE@@am__include@ @am__quote@ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelFixer.Po@am__quote@ 908 911 @AMDEP_TRUE@@am__include@ @am__quote@ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelGenerator.Po@am__quote@ 909 @AMDEP_TRUE@@am__include@ @am__quote@ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelTypeChecker.Po@am__quote@910 912 @AMDEP_TRUE@@am__include@ @am__quote@ControlStruct/$(DEPDIR)/driver_cfa_cpp-MLEMutator.Po@am__quote@ 911 913 @AMDEP_TRUE@@am__include@ @am__quote@ControlStruct/$(DEPDIR)/driver_cfa_cpp-Mutate.Po@am__quote@ … … 991 993 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-TypeofType.Po@am__quote@ 992 994 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-VarArgsType.Po@am__quote@ 995 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-VarExprReplacer.Po@am__quote@ 993 996 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-Visitor.Po@am__quote@ 994 997 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-VoidType.Po@am__quote@ 995 998 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-ZeroOneType.Po@am__quote@ 996 @AMDEP_TRUE@@am__include@ @am__quote@Tuples/$(DEPDIR)/driver_cfa_cpp- NameMatcher.Po@am__quote@999 @AMDEP_TRUE@@am__include@ @am__quote@Tuples/$(DEPDIR)/driver_cfa_cpp-Explode.Po@am__quote@ 997 1000 @AMDEP_TRUE@@am__include@ @am__quote@Tuples/$(DEPDIR)/driver_cfa_cpp-TupleAssignment.Po@am__quote@ 1001 @AMDEP_TRUE@@am__include@ @am__quote@Tuples/$(DEPDIR)/driver_cfa_cpp-TupleExpansion.Po@am__quote@ 998 1002 999 1003 .cc.o: … … 1237 1241 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o ControlStruct/driver_cfa_cpp-ForExprMutator.obj `if test -f 'ControlStruct/ForExprMutator.cc'; then $(CYGPATH_W) 'ControlStruct/ForExprMutator.cc'; else $(CYGPATH_W) '$(srcdir)/ControlStruct/ForExprMutator.cc'; fi` 1238 1242 1239 ControlStruct/driver_cfa_cpp-LabelTypeChecker.o: ControlStruct/LabelTypeChecker.cc1240 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT ControlStruct/driver_cfa_cpp-LabelTypeChecker.o -MD -MP -MF ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelTypeChecker.Tpo -c -o ControlStruct/driver_cfa_cpp-LabelTypeChecker.o `test -f 'ControlStruct/LabelTypeChecker.cc' || echo '$(srcdir)/'`ControlStruct/LabelTypeChecker.cc1241 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelTypeChecker.Tpo ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelTypeChecker.Po1242 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ControlStruct/LabelTypeChecker.cc' object='ControlStruct/driver_cfa_cpp-LabelTypeChecker.o' libtool=no @AMDEPBACKSLASH@1243 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@1244 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o ControlStruct/driver_cfa_cpp-LabelTypeChecker.o `test -f 'ControlStruct/LabelTypeChecker.cc' || echo '$(srcdir)/'`ControlStruct/LabelTypeChecker.cc1245 1246 ControlStruct/driver_cfa_cpp-LabelTypeChecker.obj: ControlStruct/LabelTypeChecker.cc1247 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT ControlStruct/driver_cfa_cpp-LabelTypeChecker.obj -MD -MP -MF ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelTypeChecker.Tpo -c -o ControlStruct/driver_cfa_cpp-LabelTypeChecker.obj `if test -f 'ControlStruct/LabelTypeChecker.cc'; then $(CYGPATH_W) 'ControlStruct/LabelTypeChecker.cc'; else $(CYGPATH_W) '$(srcdir)/ControlStruct/LabelTypeChecker.cc'; fi`1248 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelTypeChecker.Tpo ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelTypeChecker.Po1249 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ControlStruct/LabelTypeChecker.cc' object='ControlStruct/driver_cfa_cpp-LabelTypeChecker.obj' libtool=no @AMDEPBACKSLASH@1250 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@1251 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o ControlStruct/driver_cfa_cpp-LabelTypeChecker.obj `if test -f 'ControlStruct/LabelTypeChecker.cc'; then $(CYGPATH_W) 'ControlStruct/LabelTypeChecker.cc'; else $(CYGPATH_W) '$(srcdir)/ControlStruct/LabelTypeChecker.cc'; fi`1252 1253 1243 GenPoly/driver_cfa_cpp-Box.o: GenPoly/Box.cc 1254 1244 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT GenPoly/driver_cfa_cpp-Box.o -MD -MP -MF GenPoly/$(DEPDIR)/driver_cfa_cpp-Box.Tpo -c -o GenPoly/driver_cfa_cpp-Box.o `test -f 'GenPoly/Box.cc' || echo '$(srcdir)/'`GenPoly/Box.cc … … 2427 2417 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-Attribute.obj `if test -f 'SynTree/Attribute.cc'; then $(CYGPATH_W) 'SynTree/Attribute.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/Attribute.cc'; fi` 2428 2418 2419 SynTree/driver_cfa_cpp-VarExprReplacer.o: SynTree/VarExprReplacer.cc 2420 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT SynTree/driver_cfa_cpp-VarExprReplacer.o -MD -MP -MF SynTree/$(DEPDIR)/driver_cfa_cpp-VarExprReplacer.Tpo -c -o SynTree/driver_cfa_cpp-VarExprReplacer.o `test -f 'SynTree/VarExprReplacer.cc' || echo '$(srcdir)/'`SynTree/VarExprReplacer.cc 2421 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) SynTree/$(DEPDIR)/driver_cfa_cpp-VarExprReplacer.Tpo SynTree/$(DEPDIR)/driver_cfa_cpp-VarExprReplacer.Po 2422 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='SynTree/VarExprReplacer.cc' object='SynTree/driver_cfa_cpp-VarExprReplacer.o' libtool=no @AMDEPBACKSLASH@ 2423 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 2424 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-VarExprReplacer.o `test -f 'SynTree/VarExprReplacer.cc' || echo '$(srcdir)/'`SynTree/VarExprReplacer.cc 2425 2426 SynTree/driver_cfa_cpp-VarExprReplacer.obj: SynTree/VarExprReplacer.cc 2427 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT SynTree/driver_cfa_cpp-VarExprReplacer.obj -MD -MP -MF SynTree/$(DEPDIR)/driver_cfa_cpp-VarExprReplacer.Tpo -c -o SynTree/driver_cfa_cpp-VarExprReplacer.obj `if test -f 'SynTree/VarExprReplacer.cc'; then $(CYGPATH_W) 'SynTree/VarExprReplacer.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/VarExprReplacer.cc'; fi` 2428 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) SynTree/$(DEPDIR)/driver_cfa_cpp-VarExprReplacer.Tpo SynTree/$(DEPDIR)/driver_cfa_cpp-VarExprReplacer.Po 2429 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='SynTree/VarExprReplacer.cc' object='SynTree/driver_cfa_cpp-VarExprReplacer.obj' libtool=no @AMDEPBACKSLASH@ 2430 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 2431 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-VarExprReplacer.obj `if test -f 'SynTree/VarExprReplacer.cc'; then $(CYGPATH_W) 'SynTree/VarExprReplacer.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/VarExprReplacer.cc'; fi` 2432 2429 2433 Tuples/driver_cfa_cpp-TupleAssignment.o: Tuples/TupleAssignment.cc 2430 2434 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT Tuples/driver_cfa_cpp-TupleAssignment.o -MD -MP -MF Tuples/$(DEPDIR)/driver_cfa_cpp-TupleAssignment.Tpo -c -o Tuples/driver_cfa_cpp-TupleAssignment.o `test -f 'Tuples/TupleAssignment.cc' || echo '$(srcdir)/'`Tuples/TupleAssignment.cc … … 2441 2445 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o Tuples/driver_cfa_cpp-TupleAssignment.obj `if test -f 'Tuples/TupleAssignment.cc'; then $(CYGPATH_W) 'Tuples/TupleAssignment.cc'; else $(CYGPATH_W) '$(srcdir)/Tuples/TupleAssignment.cc'; fi` 2442 2446 2443 Tuples/driver_cfa_cpp-NameMatcher.o: Tuples/NameMatcher.cc 2444 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT Tuples/driver_cfa_cpp-NameMatcher.o -MD -MP -MF Tuples/$(DEPDIR)/driver_cfa_cpp-NameMatcher.Tpo -c -o Tuples/driver_cfa_cpp-NameMatcher.o `test -f 'Tuples/NameMatcher.cc' || echo '$(srcdir)/'`Tuples/NameMatcher.cc 2445 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) Tuples/$(DEPDIR)/driver_cfa_cpp-NameMatcher.Tpo Tuples/$(DEPDIR)/driver_cfa_cpp-NameMatcher.Po 2446 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='Tuples/NameMatcher.cc' object='Tuples/driver_cfa_cpp-NameMatcher.o' libtool=no @AMDEPBACKSLASH@ 2447 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 2448 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o Tuples/driver_cfa_cpp-NameMatcher.o `test -f 'Tuples/NameMatcher.cc' || echo '$(srcdir)/'`Tuples/NameMatcher.cc 2449 2450 Tuples/driver_cfa_cpp-NameMatcher.obj: Tuples/NameMatcher.cc 2451 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT Tuples/driver_cfa_cpp-NameMatcher.obj -MD -MP -MF Tuples/$(DEPDIR)/driver_cfa_cpp-NameMatcher.Tpo -c -o Tuples/driver_cfa_cpp-NameMatcher.obj `if test -f 'Tuples/NameMatcher.cc'; then $(CYGPATH_W) 'Tuples/NameMatcher.cc'; else $(CYGPATH_W) '$(srcdir)/Tuples/NameMatcher.cc'; fi` 2452 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) Tuples/$(DEPDIR)/driver_cfa_cpp-NameMatcher.Tpo Tuples/$(DEPDIR)/driver_cfa_cpp-NameMatcher.Po 2453 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='Tuples/NameMatcher.cc' object='Tuples/driver_cfa_cpp-NameMatcher.obj' libtool=no @AMDEPBACKSLASH@ 2454 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 2455 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o Tuples/driver_cfa_cpp-NameMatcher.obj `if test -f 'Tuples/NameMatcher.cc'; then $(CYGPATH_W) 'Tuples/NameMatcher.cc'; else $(CYGPATH_W) '$(srcdir)/Tuples/NameMatcher.cc'; fi` 2447 Tuples/driver_cfa_cpp-TupleExpansion.o: Tuples/TupleExpansion.cc 2448 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT Tuples/driver_cfa_cpp-TupleExpansion.o -MD -MP -MF Tuples/$(DEPDIR)/driver_cfa_cpp-TupleExpansion.Tpo -c -o Tuples/driver_cfa_cpp-TupleExpansion.o `test -f 'Tuples/TupleExpansion.cc' || echo '$(srcdir)/'`Tuples/TupleExpansion.cc 2449 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) Tuples/$(DEPDIR)/driver_cfa_cpp-TupleExpansion.Tpo Tuples/$(DEPDIR)/driver_cfa_cpp-TupleExpansion.Po 2450 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='Tuples/TupleExpansion.cc' object='Tuples/driver_cfa_cpp-TupleExpansion.o' libtool=no @AMDEPBACKSLASH@ 2451 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 2452 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o Tuples/driver_cfa_cpp-TupleExpansion.o `test -f 'Tuples/TupleExpansion.cc' || echo '$(srcdir)/'`Tuples/TupleExpansion.cc 2453 2454 Tuples/driver_cfa_cpp-TupleExpansion.obj: Tuples/TupleExpansion.cc 2455 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT Tuples/driver_cfa_cpp-TupleExpansion.obj -MD -MP -MF Tuples/$(DEPDIR)/driver_cfa_cpp-TupleExpansion.Tpo -c -o Tuples/driver_cfa_cpp-TupleExpansion.obj `if test -f 'Tuples/TupleExpansion.cc'; then $(CYGPATH_W) 'Tuples/TupleExpansion.cc'; else $(CYGPATH_W) '$(srcdir)/Tuples/TupleExpansion.cc'; fi` 2456 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) Tuples/$(DEPDIR)/driver_cfa_cpp-TupleExpansion.Tpo Tuples/$(DEPDIR)/driver_cfa_cpp-TupleExpansion.Po 2457 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='Tuples/TupleExpansion.cc' object='Tuples/driver_cfa_cpp-TupleExpansion.obj' libtool=no @AMDEPBACKSLASH@ 2458 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 2459 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o Tuples/driver_cfa_cpp-TupleExpansion.obj `if test -f 'Tuples/TupleExpansion.cc'; then $(CYGPATH_W) 'Tuples/TupleExpansion.cc'; else $(CYGPATH_W) '$(srcdir)/Tuples/TupleExpansion.cc'; fi` 2460 2461 Tuples/driver_cfa_cpp-Explode.o: Tuples/Explode.cc 2462 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT Tuples/driver_cfa_cpp-Explode.o -MD -MP -MF Tuples/$(DEPDIR)/driver_cfa_cpp-Explode.Tpo -c -o Tuples/driver_cfa_cpp-Explode.o `test -f 'Tuples/Explode.cc' || echo '$(srcdir)/'`Tuples/Explode.cc 2463 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) Tuples/$(DEPDIR)/driver_cfa_cpp-Explode.Tpo Tuples/$(DEPDIR)/driver_cfa_cpp-Explode.Po 2464 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='Tuples/Explode.cc' object='Tuples/driver_cfa_cpp-Explode.o' libtool=no @AMDEPBACKSLASH@ 2465 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 2466 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o Tuples/driver_cfa_cpp-Explode.o `test -f 'Tuples/Explode.cc' || echo '$(srcdir)/'`Tuples/Explode.cc 2467 2468 Tuples/driver_cfa_cpp-Explode.obj: Tuples/Explode.cc 2469 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT Tuples/driver_cfa_cpp-Explode.obj -MD -MP -MF Tuples/$(DEPDIR)/driver_cfa_cpp-Explode.Tpo -c -o Tuples/driver_cfa_cpp-Explode.obj `if test -f 'Tuples/Explode.cc'; then $(CYGPATH_W) 'Tuples/Explode.cc'; else $(CYGPATH_W) '$(srcdir)/Tuples/Explode.cc'; fi` 2470 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) Tuples/$(DEPDIR)/driver_cfa_cpp-Explode.Tpo Tuples/$(DEPDIR)/driver_cfa_cpp-Explode.Po 2471 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='Tuples/Explode.cc' object='Tuples/driver_cfa_cpp-Explode.obj' libtool=no @AMDEPBACKSLASH@ 2472 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 2473 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o Tuples/driver_cfa_cpp-Explode.obj `if test -f 'Tuples/Explode.cc'; then $(CYGPATH_W) 'Tuples/Explode.cc'; else $(CYGPATH_W) '$(srcdir)/Tuples/Explode.cc'; fi` 2456 2474 2457 2475 .ll.cc: -
src/Parser/ExpressionNode.cc
r3a2128f r1f44196 172 172 } // build_constantStr 173 173 174 Expression * build_field_name_FLOATINGconstant( const std::string & str ) { 175 // str is of the form A.B -> separate at the . and return member expression 176 int a, b; 177 char dot; 178 std::stringstream ss( str ); 179 ss >> a >> dot >> b; 180 UntypedMemberExpr * ret = new UntypedMemberExpr( 181 new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::SignedInt ), toString( b ) ) ), 182 new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::SignedInt ), toString( a ) ) ) ); 183 delete &str; 184 return ret; 185 } // build_field_name_FLOATINGconstant 186 187 Expression * make_field_name_fraction_constants( Expression * fieldName, Expression * fracts ) { 188 if ( fracts ) { 189 if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * >( fracts ) ) { 190 memberExpr->set_member( make_field_name_fraction_constants( fieldName, memberExpr->get_aggregate() ) ); 191 return memberExpr; 192 } else { 193 return new UntypedMemberExpr( fracts, fieldName ); 194 } 195 } 196 return fieldName; 197 } // make_field_name_fraction_constants 198 199 Expression * build_field_name_fraction_constants( Expression * fieldName, ExpressionNode * fracts ) { 200 return make_field_name_fraction_constants( fieldName, maybeMoveBuild< Expression >( fracts ) ); 201 } // build_field_name_fraction_constants 202 203 Expression * build_field_name_REALFRACTIONconstant( const std::string & str ) { 204 assert( str[0] == '.' ); 205 Expression * ret = build_constantInteger( *new std::string( str.substr(1) ) ); 206 delete &str; 207 return ret; 208 } // build_field_name_REALFRACTIONconstant 209 210 Expression * build_field_name_REALDECIMALconstant( const std::string & str ) { 211 assert( str[str.size()-1] == '.' ); 212 Expression * ret = build_constantInteger( *new std::string( str.substr( 0, str.size()-1 ) ) ); 213 delete &str; 214 return ret; 215 } // build_field_name_REALDECIMALconstant 216 174 217 NameExpr * build_varref( const string *name, bool labelp ) { 175 218 NameExpr *expr = new NameExpr( *name, nullptr ); … … 198 241 } 199 242 200 Expression *build_fieldSel( ExpressionNode *expr_node, NameExpr *member ) { 201 UntypedMemberExpr *ret = new UntypedMemberExpr( member->get_name(), maybeMoveBuild< Expression >(expr_node) ); 202 delete member; 203 return ret; 204 } 205 206 Expression *build_pfieldSel( ExpressionNode *expr_node, NameExpr *member ) { 243 Expression *build_fieldSel( ExpressionNode *expr_node, Expression *member ) { 244 UntypedMemberExpr *ret = new UntypedMemberExpr( member, maybeMoveBuild< Expression >(expr_node) ); 245 return ret; 246 } 247 248 Expression *build_pfieldSel( ExpressionNode *expr_node, Expression *member ) { 207 249 UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) ); 208 250 deref->get_args().push_back( maybeMoveBuild< Expression >(expr_node) ); 209 UntypedMemberExpr *ret = new UntypedMemberExpr( member->get_name(), deref ); 210 delete member; 251 UntypedMemberExpr *ret = new UntypedMemberExpr( member, deref ); 211 252 return ret; 212 253 } -
src/Parser/ParseNode.h
r3a2128f r1f44196 155 155 Expression * build_constantChar( const std::string &str ); 156 156 ConstantExpr * build_constantStr( const std::string &str ); 157 Expression * build_field_name_FLOATINGconstant( const std::string & str ); 158 Expression * build_field_name_fraction_constants( Expression * fieldName, ExpressionNode * fracts ); 159 Expression * build_field_name_REALFRACTIONconstant( const std::string & str ); 160 Expression * build_field_name_REALDECIMALconstant( const std::string & str ); 157 161 158 162 NameExpr * build_varref( const std::string * name, bool labelp = false ); … … 160 164 161 165 Expression * build_cast( DeclarationNode * decl_node, ExpressionNode * expr_node ); 162 Expression * build_fieldSel( ExpressionNode * expr_node, NameExpr* member );163 Expression * build_pfieldSel( ExpressionNode * expr_node, NameExpr* member );166 Expression * build_fieldSel( ExpressionNode * expr_node, Expression * member ); 167 Expression * build_pfieldSel( ExpressionNode * expr_node, Expression * member ); 164 168 Expression * build_addressOf( ExpressionNode * expr_node ); 165 169 Expression * build_sizeOfexpr( ExpressionNode * expr_node ); … … 383 387 //############################################################################## 384 388 385 template< typename SynTreeType, typename NodeType >386 void buildList( const NodeType * firstNode, std::list< SynTreeType *> &outputList ) {389 template< typename SynTreeType, typename NodeType, template< typename, typename...> class Container, typename... Args > 390 void buildList( const NodeType * firstNode, Container< SynTreeType *, Args... > &outputList ) { 387 391 SemanticError errors; 388 std::back_insert_iterator< std::list< SynTreeType *> > out( outputList );392 std::back_insert_iterator< Container< SynTreeType *, Args... > > out( outputList ); 389 393 const NodeType * cur = firstNode; 390 394 -
src/Parser/TypeData.cc
r3a2128f r1f44196 385 385 } // TypeData::print 386 386 387 void buildForall( const DeclarationNode * firstNode, list< TypeDecl* > &outputList ) { 387 template< typename ForallList > 388 void buildForall( const DeclarationNode * firstNode, ForallList &outputList ) { 388 389 buildList( firstNode, outputList ); 389 for ( list< TypeDecl* >::iterator i = outputList.begin(); i != outputList.end(); ++i ) { 390 if ( (*i)->get_kind() == TypeDecl::Any ) { 390 for ( typename ForallList::iterator i = outputList.begin(); i != outputList.end(); ++i ) { 391 TypeDecl * td = static_cast<TypeDecl*>(*i); 392 if ( td->get_kind() == TypeDecl::Any ) { 391 393 // add assertion parameters to `type' tyvars in reverse order 392 394 // add dtor: void ^?{}(T *) 393 395 FunctionType * dtorType = new FunctionType( Type::Qualifiers(), false ); 394 dtorType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ) ), nullptr ) );395 (*i)->get_assertions().push_front( new FunctionDecl( "^?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, dtorType, nullptr, false, false ) );396 dtorType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), td->get_name(), *i ) ), nullptr ) ); 397 td->get_assertions().push_front( new FunctionDecl( "^?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, dtorType, nullptr, false, false ) ); 396 398 397 399 // add copy ctor: void ?{}(T *, T) 398 400 FunctionType * copyCtorType = new FunctionType( Type::Qualifiers(), false ); 399 copyCtorType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ) ), nullptr ) );400 copyCtorType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ), nullptr ) );401 (*i)->get_assertions().push_front( new FunctionDecl( "?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, copyCtorType, nullptr, false, false ) );401 copyCtorType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), td->get_name(), *i ) ), nullptr ) ); 402 copyCtorType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), td->get_name(), *i ), nullptr ) ); 403 td->get_assertions().push_front( new FunctionDecl( "?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, copyCtorType, nullptr, false, false ) ); 402 404 403 405 // add default ctor: void ?{}(T *) 404 406 FunctionType * ctorType = new FunctionType( Type::Qualifiers(), false ); 405 ctorType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ) ), nullptr ) );406 (*i)->get_assertions().push_front( new FunctionDecl( "?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, ctorType, nullptr, false, false ) );407 ctorType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), td->get_name(), *i ) ), nullptr ) ); 408 td->get_assertions().push_front( new FunctionDecl( "?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, ctorType, nullptr, false, false ) ); 407 409 408 410 // add assignment operator: T * ?=?(T *, T) 409 411 FunctionType * assignType = new FunctionType( Type::Qualifiers(), false ); 410 assignType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ) ), nullptr ) );411 assignType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ), nullptr ) );412 assignType->get_returnVals().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ), nullptr ) );413 (*i)->get_assertions().push_front( new FunctionDecl( "?=?", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, assignType, nullptr, false, false ) );412 assignType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), td->get_name(), *i ) ), nullptr ) ); 413 assignType->get_parameters().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), td->get_name(), *i ), nullptr ) ); 414 assignType->get_returnVals().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new TypeInstType( Type::Qualifiers(), td->get_name(), *i ), nullptr ) ); 415 td->get_assertions().push_front( new FunctionDecl( "?=?", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, assignType, nullptr, false, false ) ); 414 416 } // if 415 417 } // for … … 515 517 // character types. The implementation shall define char to have the same range, representation, and behavior as 516 518 // either signed char or unsigned char. 517 static BasicType::Kind chartype[] = { BasicType::SignedChar, BasicType::UnsignedChar, BasicType::Char }; 519 static BasicType::Kind chartype[] = { BasicType::SignedChar, BasicType::UnsignedChar, BasicType::Char }; 518 520 519 521 if ( td->length != DeclarationNode::NoLength ) { -
src/Parser/parser.cc
r3a2128f r1f44196 1030 1030 static const yytype_uint16 yyrline[] = 1031 1031 { 1032 0, 30 6, 306, 310, 317, 318, 319, 320, 321, 325,1033 32 6, 327, 331, 332, 336, 337, 341, 342, 346, 350,1034 35 1, 362, 364, 366, 367, 369, 374, 375, 381, 383,1035 38 5, 386, 387, 389, 390, 392, 394, 396, 405, 406,1036 41 2, 413, 417, 418, 422, 424, 426, 428, 430, 432,1037 43 4, 439, 441, 443, 447, 449, 453, 456, 458, 460,1038 4 65, 478, 480, 482, 484, 486, 488, 490, 492, 494,1039 496, 498, 505, 506, 512, 513, 514, 515, 519, 520,1040 5 27, 528, 530, 532, 537, 538, 540, 545, 546, 548,1041 55 3, 554, 556, 558, 560, 565, 566, 568, 573, 574,1042 5 79, 580, 585, 586, 591, 592, 597, 598, 603, 604,1043 6 07, 614, 619, 620, 628, 629, 633, 634, 635, 636,1044 6 37, 638, 639, 640, 641, 642, 643, 644, 654, 656,1045 66 1, 662, 667, 668, 674, 675, 681, 682, 683, 684,1046 6 85, 686, 687, 688, 689, 699, 706, 708, 718, 719,1047 7 24, 726, 732, 734, 738, 739, 744, 749, 752, 754,1048 7 56, 766, 768, 779, 780, 782, 786, 788, 792, 793,1049 798, 799, 803, 808, 809, 813, 815, 821, 822, 826,1050 8 28, 830, 832, 838, 839, 843, 845, 850, 852, 854,1051 8 59, 861, 866, 868, 872, 875, 879, 882, 886, 888,1052 89 0, 892, 897, 899, 901, 906, 908, 910, 912, 914,1053 9 19, 921, 923, 925, 930, 942, 943, 948, 950, 955,1054 9 59, 961, 963, 965, 967, 973, 974, 980, 981, 985,1055 9 86, 991, 993, 999, 1000, 1002, 1007, 1012, 1022, 1024,1056 10 28, 1029, 1034, 1036, 1040, 1041, 1045, 1047, 1051, 1052,1057 10 56, 1057, 1061, 1062, 1077, 1078, 1079, 1080, 1081, 1085,1058 109 0, 1097, 1107, 1112, 1117, 1125, 1130, 1135, 1140, 1145,1059 11 75, 1180, 1187, 1189, 1196, 1201, 1206, 1217, 1222, 1227,1060 123 2, 1237, 1246, 1251, 1259, 1260, 1261, 1262, 1268, 1273,1061 128 1, 1282, 1283, 1284, 1288, 1289, 1290, 1291, 1296, 1297,1062 13 06, 1307, 1312, 1313, 1318, 1320, 1322, 1324, 1326, 1329,1063 13 28, 1340, 1341, 1343, 1353, 1354, 1359, 1361, 1363, 1365,1064 13 67, 1370, 1372, 1375, 1380, 1382, 1384, 1386, 1388, 1390,1065 139 2, 1394, 1396, 1398, 1400, 1402, 1404, 1406, 1408, 1414,1066 14 15, 1417, 1419, 1421, 1426, 1427, 1433, 1434, 1436, 1438,1067 144 3, 1445, 1447, 1449, 1454, 1455, 1457, 1459, 1464, 1465,1068 14 67, 1472, 1473, 1475, 1477, 1482, 1484, 1486, 1491, 1492,1069 1 496, 1498, 1504, 1503, 1507, 1509, 1514, 1516, 1522, 1523,1070 15 28, 1529, 1531, 1532, 1541, 1542, 1544, 1546, 1551, 1553,1071 15 59, 1560, 1562, 1565, 1568, 1573, 1574, 1579, 1584, 1588,1072 159 0, 1596, 1595, 1602, 1604, 1610, 1611, 1619, 1620, 1624,1073 16 25, 1626, 1628, 1630, 1637, 1638, 1640, 1642, 1647, 1648,1074 16 54, 1655, 1659, 1660, 1665, 1666, 1667, 1669, 1677, 1678,1075 168 0, 1683, 1685, 1689, 1690, 1691, 1693, 1695, 1699, 1704,1076 171 2, 1713, 1722, 1724, 1729, 1730, 1731, 1735, 1736, 1737,1077 174 1, 1742, 1743, 1747, 1748, 1749, 1754, 1755, 1756, 1757,1078 176 3, 1764, 1766, 1771, 1772, 1777, 1778, 1779, 1780, 1781,1079 1 796, 1797, 1802, 1803, 1809, 1811, 1814, 1816, 1818, 1841,1080 184 2, 1844, 1846, 1851, 1852, 1854, 1859, 1864, 1865, 1871,1081 187 0, 1874, 1878, 1880, 1882, 1888, 1889, 1894, 1899, 1901,1082 19 06, 1908, 1909, 1911, 1916, 1918, 1920, 1925, 1927, 1932,1083 19 37, 1945, 1951, 1950, 1964, 1965, 1970, 1971, 1975, 1980,1084 19 85, 1993, 1998, 2009, 2010, 2015, 2016, 2022, 2023, 2027,1085 20 28, 2029, 2032, 2031, 2042, 2051, 2057, 2063, 2072, 2078,1086 20 84, 2090, 2096, 2104, 2110, 2118, 2124, 2133, 2134, 2135,1087 21 39, 2143, 2145, 2150, 2151, 2155, 2156, 2161, 2167, 2168,1088 217 1, 2173, 2174, 2178, 2179, 2180, 2181, 2215, 2217, 2218,1089 222 0, 2225, 2230, 2235, 2237, 2239, 2244, 2246, 2248, 2250,1090 22 55, 2257, 2266, 2268, 2269, 2274, 2276, 2278, 2283, 2285,1091 22 87, 2292, 2294, 2296, 2305, 2306, 2307, 2311, 2313, 2315,1092 232 0, 2322, 2324, 2329, 2331, 2333, 2348, 2350, 2351, 2353,1093 23 58, 2359, 2364, 2366, 2368, 2373, 2375, 2377, 2379, 2384,1094 23 86, 2388, 2398, 2400, 2401, 2403, 2408, 2410, 2412, 2417,1095 24 19, 2421, 2423, 2428, 2430, 2432, 2463, 2465, 2466, 2468,1096 247 3, 2478, 2486, 2488, 2490, 2495, 2497, 2502, 2504, 2518,1097 25 19, 2521, 2526, 2528, 2530, 2532, 2534, 2539, 2540, 2542,1098 25 44, 2549, 2551, 2553, 2559, 2561, 2563, 2567, 2569, 2571,1099 257 3, 2587, 2588, 2590, 2595, 2597, 2599, 2601, 2603, 2608,1100 26 09, 2611, 2613, 2618, 2620, 2622, 2628, 2629, 2631, 2640,1101 264 3, 2645, 2648, 2650, 2652, 2665, 2666, 2668, 2673, 2675,1102 26 77, 2679, 2681, 2686, 2687, 2689, 2691, 2696, 2698, 2706,1103 27 07, 2708, 2713, 2714, 2718, 2720, 2722, 2724, 2726, 2728,1104 27 35, 2737, 2739, 2741, 2743, 2746, 2748, 2750, 2752, 2754,1105 27 59, 2761, 2763, 2768, 2794, 2795, 2797, 2801, 2802, 2806,1106 28 08, 2810, 2812, 2814, 2816, 2823, 2825, 2827, 2829, 2831,1107 283 3, 2838, 2845, 2847, 2865, 2867, 2872, 28731032 0, 305, 305, 309, 316, 317, 318, 319, 320, 324, 1033 325, 326, 330, 331, 335, 336, 340, 341, 345, 349, 1034 350, 361, 363, 365, 366, 368, 373, 374, 380, 382, 1035 384, 386, 388, 390, 392, 394, 396, 398, 407, 408, 1036 414, 415, 419, 420, 424, 425, 427, 429, 431, 433, 1037 435, 440, 442, 444, 450, 451, 459, 462, 464, 466, 1038 471, 484, 486, 488, 490, 492, 494, 496, 498, 500, 1039 502, 504, 511, 512, 518, 519, 520, 521, 525, 526, 1040 533, 534, 536, 538, 543, 544, 546, 551, 552, 554, 1041 559, 560, 562, 564, 566, 571, 572, 574, 579, 580, 1042 585, 586, 591, 592, 597, 598, 603, 604, 609, 610, 1043 613, 620, 625, 626, 634, 635, 639, 640, 641, 642, 1044 643, 644, 645, 646, 647, 648, 649, 650, 660, 662, 1045 667, 668, 673, 674, 680, 681, 687, 688, 689, 690, 1046 691, 692, 693, 694, 695, 705, 712, 714, 724, 725, 1047 730, 732, 738, 740, 744, 745, 750, 755, 758, 760, 1048 762, 772, 774, 785, 786, 788, 792, 794, 798, 799, 1049 804, 805, 809, 814, 815, 819, 821, 827, 828, 832, 1050 834, 836, 838, 844, 845, 849, 851, 856, 858, 860, 1051 865, 867, 872, 874, 878, 881, 885, 888, 892, 894, 1052 896, 898, 903, 905, 907, 912, 914, 916, 918, 920, 1053 925, 927, 929, 931, 936, 948, 949, 954, 956, 961, 1054 965, 967, 969, 971, 973, 979, 980, 986, 987, 991, 1055 992, 997, 999, 1005, 1006, 1008, 1013, 1018, 1028, 1030, 1056 1034, 1035, 1040, 1042, 1046, 1047, 1051, 1053, 1057, 1058, 1057 1062, 1063, 1067, 1068, 1083, 1084, 1085, 1086, 1087, 1091, 1058 1096, 1103, 1113, 1118, 1123, 1131, 1136, 1141, 1146, 1151, 1059 1181, 1186, 1193, 1195, 1202, 1207, 1212, 1223, 1228, 1233, 1060 1238, 1243, 1252, 1257, 1265, 1266, 1267, 1268, 1274, 1279, 1061 1287, 1288, 1289, 1290, 1294, 1295, 1296, 1297, 1302, 1303, 1062 1312, 1313, 1318, 1319, 1324, 1326, 1328, 1330, 1332, 1335, 1063 1334, 1346, 1347, 1349, 1359, 1360, 1365, 1367, 1369, 1371, 1064 1373, 1376, 1378, 1381, 1386, 1388, 1390, 1392, 1394, 1396, 1065 1398, 1400, 1402, 1404, 1406, 1408, 1410, 1412, 1414, 1420, 1066 1421, 1423, 1425, 1427, 1432, 1433, 1439, 1440, 1442, 1444, 1067 1449, 1451, 1453, 1455, 1460, 1461, 1463, 1465, 1470, 1471, 1068 1473, 1478, 1479, 1481, 1483, 1488, 1490, 1492, 1497, 1498, 1069 1502, 1504, 1510, 1509, 1513, 1515, 1520, 1522, 1528, 1529, 1070 1534, 1535, 1537, 1538, 1547, 1548, 1550, 1552, 1557, 1559, 1071 1565, 1566, 1568, 1571, 1574, 1579, 1580, 1585, 1590, 1594, 1072 1596, 1602, 1601, 1608, 1610, 1616, 1617, 1625, 1626, 1630, 1073 1631, 1632, 1634, 1636, 1643, 1644, 1646, 1648, 1653, 1654, 1074 1660, 1661, 1665, 1666, 1671, 1672, 1673, 1675, 1683, 1684, 1075 1686, 1689, 1691, 1695, 1696, 1697, 1699, 1701, 1705, 1710, 1076 1718, 1719, 1728, 1730, 1735, 1736, 1737, 1741, 1742, 1743, 1077 1747, 1748, 1749, 1753, 1754, 1755, 1760, 1761, 1762, 1763, 1078 1769, 1770, 1772, 1777, 1778, 1783, 1784, 1785, 1786, 1787, 1079 1802, 1803, 1808, 1809, 1815, 1817, 1820, 1822, 1824, 1847, 1080 1848, 1850, 1852, 1857, 1858, 1860, 1865, 1870, 1871, 1877, 1081 1876, 1880, 1884, 1886, 1888, 1894, 1895, 1900, 1905, 1907, 1082 1912, 1914, 1915, 1917, 1922, 1924, 1926, 1931, 1933, 1938, 1083 1943, 1951, 1957, 1956, 1970, 1971, 1976, 1977, 1981, 1986, 1084 1991, 1999, 2004, 2015, 2016, 2021, 2022, 2028, 2029, 2033, 1085 2034, 2035, 2038, 2037, 2048, 2057, 2063, 2069, 2078, 2084, 1086 2090, 2096, 2102, 2110, 2116, 2124, 2130, 2139, 2140, 2141, 1087 2145, 2149, 2151, 2156, 2157, 2161, 2162, 2167, 2173, 2174, 1088 2177, 2179, 2180, 2184, 2185, 2186, 2187, 2221, 2223, 2224, 1089 2226, 2231, 2236, 2241, 2243, 2245, 2250, 2252, 2254, 2256, 1090 2261, 2263, 2272, 2274, 2275, 2280, 2282, 2284, 2289, 2291, 1091 2293, 2298, 2300, 2302, 2311, 2312, 2313, 2317, 2319, 2321, 1092 2326, 2328, 2330, 2335, 2337, 2339, 2354, 2356, 2357, 2359, 1093 2364, 2365, 2370, 2372, 2374, 2379, 2381, 2383, 2385, 2390, 1094 2392, 2394, 2404, 2406, 2407, 2409, 2414, 2416, 2418, 2423, 1095 2425, 2427, 2429, 2434, 2436, 2438, 2469, 2471, 2472, 2474, 1096 2479, 2484, 2492, 2494, 2496, 2501, 2503, 2508, 2510, 2524, 1097 2525, 2527, 2532, 2534, 2536, 2538, 2540, 2545, 2546, 2548, 1098 2550, 2555, 2557, 2559, 2565, 2567, 2569, 2573, 2575, 2577, 1099 2579, 2593, 2594, 2596, 2601, 2603, 2605, 2607, 2609, 2614, 1100 2615, 2617, 2619, 2624, 2626, 2628, 2634, 2635, 2637, 2646, 1101 2649, 2651, 2654, 2656, 2658, 2671, 2672, 2674, 2679, 2681, 1102 2683, 2685, 2687, 2692, 2693, 2695, 2697, 2702, 2704, 2712, 1103 2713, 2714, 2719, 2720, 2724, 2726, 2728, 2730, 2732, 2734, 1104 2741, 2743, 2745, 2747, 2749, 2752, 2754, 2756, 2758, 2760, 1105 2765, 2767, 2769, 2774, 2800, 2801, 2803, 2807, 2808, 2812, 1106 2814, 2816, 2818, 2820, 2822, 2829, 2831, 2833, 2835, 2837, 1107 2839, 2844, 2851, 2853, 2871, 2873, 2878, 2879 1108 1108 }; 1109 1109 #endif … … 4928 4928 4929 4929 /* Line 1806 of yacc.c */ 4930 #line 30 6"parser.yy"4930 #line 305 "parser.yy" 4931 4931 { typedefTable.enterScope(); } 4932 4932 break; … … 4935 4935 4936 4936 /* Line 1806 of yacc.c */ 4937 #line 3 10"parser.yy"4937 #line 309 "parser.yy" 4938 4938 { typedefTable.leaveScope(); } 4939 4939 break; … … 4942 4942 4943 4943 /* Line 1806 of yacc.c */ 4944 #line 316 "parser.yy" 4945 { (yyval.en) = new ExpressionNode( build_constantInteger( *(yyvsp[(1) - (1)].tok) ) ); } 4946 break; 4947 4948 case 5: 4949 4950 /* Line 1806 of yacc.c */ 4944 4951 #line 317 "parser.yy" 4945 { (yyval.en) = new ExpressionNode( build_constant Integer( *(yyvsp[(1) - (1)].tok) ) ); }4946 break; 4947 4948 case 5:4952 { (yyval.en) = new ExpressionNode( build_constantFloat( *(yyvsp[(1) - (1)].tok) ) ); } 4953 break; 4954 4955 case 6: 4949 4956 4950 4957 /* Line 1806 of yacc.c */ … … 4953 4960 break; 4954 4961 4955 case 6:4962 case 7: 4956 4963 4957 4964 /* Line 1806 of yacc.c */ … … 4960 4967 break; 4961 4968 4962 case 7:4969 case 8: 4963 4970 4964 4971 /* Line 1806 of yacc.c */ 4965 4972 #line 320 "parser.yy" 4966 { (yyval.en) = new ExpressionNode( build_constantFloat( *(yyvsp[(1) - (1)].tok) ) ); }4967 break;4968 4969 case 8:4970 4971 /* Line 1806 of yacc.c */4972 #line 321 "parser.yy"4973 4973 { (yyval.en) = new ExpressionNode( build_constantChar( *(yyvsp[(1) - (1)].tok) ) ); } 4974 4974 break; … … 4977 4977 4978 4978 /* Line 1806 of yacc.c */ 4979 #line 34 6"parser.yy"4979 #line 345 "parser.yy" 4980 4980 { (yyval.constant) = build_constantStr( *(yyvsp[(1) - (1)].str) ); } 4981 4981 break; … … 4984 4984 4985 4985 /* Line 1806 of yacc.c */ 4986 #line 3 50"parser.yy"4986 #line 349 "parser.yy" 4987 4987 { (yyval.str) = (yyvsp[(1) - (1)].tok); } 4988 4988 break; … … 4991 4991 4992 4992 /* Line 1806 of yacc.c */ 4993 #line 35 2"parser.yy"4993 #line 351 "parser.yy" 4994 4994 { 4995 4995 appendStr( (yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].tok) ); // append 2nd juxtaposed string to 1st … … 5002 5002 5003 5003 /* Line 1806 of yacc.c */ 5004 #line 36 3"parser.yy"5004 #line 362 "parser.yy" 5005 5005 { (yyval.en) = new ExpressionNode( build_varref( (yyvsp[(1) - (1)].tok) ) ); } 5006 5006 break; … … 5009 5009 5010 5010 /* Line 1806 of yacc.c */ 5011 #line 36 5"parser.yy"5011 #line 364 "parser.yy" 5012 5012 { (yyval.en) = new ExpressionNode( build_varref( (yyvsp[(1) - (1)].tok) ) ); } 5013 5013 break; … … 5016 5016 5017 5017 /* Line 1806 of yacc.c */ 5018 #line 36 8"parser.yy"5018 #line 367 "parser.yy" 5019 5019 { (yyval.en) = (yyvsp[(2) - (3)].en); } 5020 5020 break; … … 5023 5023 5024 5024 /* Line 1806 of yacc.c */ 5025 #line 3 70"parser.yy"5025 #line 369 "parser.yy" 5026 5026 { (yyval.en) = new ExpressionNode( build_valexpr( (yyvsp[(2) - (3)].sn) ) ); } 5027 5027 break; … … 5030 5030 5031 5031 /* Line 1806 of yacc.c */ 5032 #line 3 80"parser.yy"5032 #line 379 "parser.yy" 5033 5033 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Index, (yyvsp[(1) - (6)].en), (yyvsp[(4) - (6)].en) ) ); } 5034 5034 break; … … 5037 5037 5038 5038 /* Line 1806 of yacc.c */ 5039 #line 38 2"parser.yy"5039 #line 381 "parser.yy" 5040 5040 { (yyval.en) = new ExpressionNode( build_func( (yyvsp[(1) - (4)].en), (yyvsp[(3) - (4)].en) ) ); } 5041 5041 break; … … 5044 5044 5045 5045 /* Line 1806 of yacc.c */ 5046 #line 38 4"parser.yy"5046 #line 383 "parser.yy" 5047 5047 { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(1) - (3)].en), build_varref( (yyvsp[(3) - (3)].tok) ) ) ); } 5048 5048 break; 5049 5049 5050 case 30: 5051 5052 /* Line 1806 of yacc.c */ 5053 #line 385 "parser.yy" 5054 { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(1) - (7)].en), build_tuple( (yyvsp[(5) - (7)].en) ) ) ); } 5055 break; 5056 5057 case 31: 5058 5059 /* Line 1806 of yacc.c */ 5060 #line 387 "parser.yy" 5061 { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(1) - (2)].en), build_field_name_REALFRACTIONconstant( *(yyvsp[(2) - (2)].tok) ) ) ); } 5062 break; 5063 5050 5064 case 32: 5051 5065 5052 5066 /* Line 1806 of yacc.c */ 5053 #line 38 8"parser.yy"5067 #line 389 "parser.yy" 5054 5068 { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[(1) - (3)].en), build_varref( (yyvsp[(3) - (3)].tok) ) ) ); } 5055 5069 break; 5056 5070 5071 case 33: 5072 5073 /* Line 1806 of yacc.c */ 5074 #line 391 "parser.yy" 5075 { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[(1) - (7)].en), build_tuple( (yyvsp[(5) - (7)].en) ) ) ); } 5076 break; 5077 5057 5078 case 34: 5058 5079 5059 5080 /* Line 1806 of yacc.c */ 5060 #line 39 1"parser.yy"5081 #line 393 "parser.yy" 5061 5082 { (yyval.en) = new ExpressionNode( build_unary_ptr( OperKinds::IncrPost, (yyvsp[(1) - (2)].en) ) ); } 5062 5083 break; … … 5065 5086 5066 5087 /* Line 1806 of yacc.c */ 5067 #line 39 3"parser.yy"5088 #line 395 "parser.yy" 5068 5089 { (yyval.en) = new ExpressionNode( build_unary_ptr( OperKinds::DecrPost, (yyvsp[(1) - (2)].en) ) ); } 5069 5090 break; … … 5072 5093 5073 5094 /* Line 1806 of yacc.c */ 5074 #line 39 5"parser.yy"5095 #line 397 "parser.yy" 5075 5096 { (yyval.en) = new ExpressionNode( build_compoundLiteral( (yyvsp[(2) - (7)].decl), new InitializerNode( (yyvsp[(5) - (7)].in), true ) ) ); } 5076 5097 break; … … 5079 5100 5080 5101 /* Line 1806 of yacc.c */ 5081 #line 39 7"parser.yy"5102 #line 399 "parser.yy" 5082 5103 { 5083 5104 Token fn; … … 5090 5111 5091 5112 /* Line 1806 of yacc.c */ 5092 #line 40 7"parser.yy"5113 #line 409 "parser.yy" 5093 5114 { (yyval.en) = (ExpressionNode *)( (yyvsp[(1) - (3)].en)->set_last( (yyvsp[(3) - (3)].en) )); } 5094 5115 break; … … 5097 5118 5098 5119 /* Line 1806 of yacc.c */ 5099 #line 41 2"parser.yy"5120 #line 414 "parser.yy" 5100 5121 { (yyval.en) = 0; } 5101 5122 break; … … 5104 5125 5105 5126 /* Line 1806 of yacc.c */ 5106 #line 4 18"parser.yy"5127 #line 420 "parser.yy" 5107 5128 { (yyval.en) = (ExpressionNode *)(yyvsp[(1) - (3)].en)->set_last( (yyvsp[(3) - (3)].en) ); } 5108 5129 break; 5109 5130 5110 case 44:5111 5112 /* Line 1806 of yacc.c */5113 #line 423 "parser.yy"5114 { (yyval.en) = new ExpressionNode( build_varref( (yyvsp[(1) - (1)].tok) ) ); }5115 break;5116 5117 5131 case 45: 5118 5132 5119 5133 /* Line 1806 of yacc.c */ 5120 #line 42 5"parser.yy"5121 { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(2) - (2)].en), build_varref( (yyvsp[(1) - (2)].tok) ) ) ); }5134 #line 426 "parser.yy" 5135 { (yyval.en) = new ExpressionNode( build_fieldSel( new ExpressionNode( build_field_name_REALDECIMALconstant( *(yyvsp[(1) - (2)].tok) ) ), maybeMoveBuild<Expression>( (yyvsp[(2) - (2)].en) ) ) ); } 5122 5136 break; 5123 5137 … … 5125 5139 5126 5140 /* Line 1806 of yacc.c */ 5127 #line 42 7"parser.yy"5128 { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(4) - (6)].en), build_varref( (yyvsp[(1) - (6)].tok) ) ) ); }5141 #line 428 "parser.yy" 5142 { (yyval.en) = new ExpressionNode( build_fieldSel( new ExpressionNode( build_field_name_REALDECIMALconstant( *(yyvsp[(1) - (6)].tok) ) ), build_tuple( (yyvsp[(4) - (6)].en) ) ) ); } 5129 5143 break; 5130 5144 … … 5132 5146 5133 5147 /* Line 1806 of yacc.c */ 5134 #line 4 29"parser.yy"5135 { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[( 3) - (3)].en), build_varref( (yyvsp[(1) - (3)].tok) ) ) ); }5148 #line 430 "parser.yy" 5149 { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(1) - (3)].en), maybeMoveBuild<Expression>( (yyvsp[(3) - (3)].en) ) ) ); } 5136 5150 break; 5137 5151 … … 5139 5153 5140 5154 /* Line 1806 of yacc.c */ 5141 #line 43 1"parser.yy"5142 { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[( 5) - (7)].en), build_varref( (yyvsp[(1) - (7)].tok) ) ) ); }5155 #line 432 "parser.yy" 5156 { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(1) - (7)].en), build_tuple( (yyvsp[(5) - (7)].en) ) ) ); } 5143 5157 break; 5144 5158 … … 5146 5160 5147 5161 /* Line 1806 of yacc.c */ 5148 #line 43 3"parser.yy"5149 { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[( 3) - (3)].en), build_varref( (yyvsp[(1) - (3)].tok) ) ) ); }5162 #line 434 "parser.yy" 5163 { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[(1) - (3)].en), maybeMoveBuild<Expression>( (yyvsp[(3) - (3)].en) ) ) ); } 5150 5164 break; 5151 5165 … … 5153 5167 5154 5168 /* Line 1806 of yacc.c */ 5155 #line 43 5"parser.yy"5156 { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[( 5) - (7)].en), build_varref( (yyvsp[(1) - (7)].tok) ) ) ); }5169 #line 436 "parser.yy" 5170 { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[(1) - (7)].en), build_tuple( (yyvsp[(5) - (7)].en) ) ) ); } 5157 5171 break; 5158 5172 … … 5160 5174 5161 5175 /* Line 1806 of yacc.c */ 5162 #line 44 0"parser.yy"5163 { (yyval. tok) = (yyvsp[(1) - (2)].tok); }5176 #line 441 "parser.yy" 5177 { (yyval.en) = new ExpressionNode( build_field_name_fraction_constants( build_constantInteger( *(yyvsp[(1) - (2)].tok) ), (yyvsp[(2) - (2)].en) ) ); } 5164 5178 break; 5165 5179 … … 5167 5181 5168 5182 /* Line 1806 of yacc.c */ 5169 #line 44 2"parser.yy"5170 { (yyval. tok) = (yyvsp[(1) - (2)].tok); }5183 #line 443 "parser.yy" 5184 { (yyval.en) = new ExpressionNode( build_field_name_fraction_constants( build_field_name_FLOATINGconstant( *(yyvsp[(1) - (2)].tok) ), (yyvsp[(2) - (2)].en) ) ); } 5171 5185 break; 5172 5186 … … 5174 5188 5175 5189 /* Line 1806 of yacc.c */ 5176 #line 444 "parser.yy" 5177 { (yyval.tok) = (yyvsp[(1) - (2)].tok); } 5190 #line 445 "parser.yy" 5191 { (yyval.en) = new ExpressionNode( build_field_name_fraction_constants( build_varref( (yyvsp[(1) - (2)].tok) ), (yyvsp[(2) - (2)].en) ) ); } 5192 break; 5193 5194 case 54: 5195 5196 /* Line 1806 of yacc.c */ 5197 #line 450 "parser.yy" 5198 { (yyval.en) = nullptr; } 5199 break; 5200 5201 case 55: 5202 5203 /* Line 1806 of yacc.c */ 5204 #line 452 "parser.yy" 5205 { 5206 Expression * constant = build_field_name_REALFRACTIONconstant( *(yyvsp[(2) - (2)].tok) ); 5207 (yyval.en) = (yyvsp[(1) - (2)].en) != nullptr ? new ExpressionNode( build_fieldSel( (yyvsp[(1) - (2)].en), constant ) ) : new ExpressionNode( constant ); 5208 } 5178 5209 break; 5179 5210 … … 5181 5212 5182 5213 /* Line 1806 of yacc.c */ 5183 #line 4 57"parser.yy"5214 #line 463 "parser.yy" 5184 5215 { (yyval.en) = (yyvsp[(1) - (1)].en); } 5185 5216 break; … … 5188 5219 5189 5220 /* Line 1806 of yacc.c */ 5190 #line 4 59"parser.yy"5221 #line 465 "parser.yy" 5191 5222 { (yyval.en) = new ExpressionNode( (yyvsp[(1) - (1)].constant) ); } 5192 5223 break; … … 5195 5226 5196 5227 /* Line 1806 of yacc.c */ 5197 #line 46 1"parser.yy"5228 #line 467 "parser.yy" 5198 5229 { (yyval.en) = (yyvsp[(2) - (2)].en)->set_extension( true ); } 5199 5230 break; … … 5202 5233 5203 5234 /* Line 1806 of yacc.c */ 5204 #line 4 66"parser.yy"5235 #line 472 "parser.yy" 5205 5236 { 5206 5237 switch ( (yyvsp[(1) - (2)].op) ) { … … 5220 5251 5221 5252 /* Line 1806 of yacc.c */ 5222 #line 4 79"parser.yy"5253 #line 485 "parser.yy" 5223 5254 { (yyval.en) = new ExpressionNode( build_unary_val( (yyvsp[(1) - (2)].op), (yyvsp[(2) - (2)].en) ) ); } 5224 5255 break; … … 5227 5258 5228 5259 /* Line 1806 of yacc.c */ 5229 #line 48 1"parser.yy"5260 #line 487 "parser.yy" 5230 5261 { (yyval.en) = new ExpressionNode( build_unary_ptr( OperKinds::Incr, (yyvsp[(2) - (2)].en) ) ); } 5231 5262 break; … … 5234 5265 5235 5266 /* Line 1806 of yacc.c */ 5236 #line 48 3"parser.yy"5267 #line 489 "parser.yy" 5237 5268 { (yyval.en) = new ExpressionNode( build_unary_ptr( OperKinds::Decr, (yyvsp[(2) - (2)].en) ) ); } 5238 5269 break; … … 5241 5272 5242 5273 /* Line 1806 of yacc.c */ 5243 #line 4 85"parser.yy"5274 #line 491 "parser.yy" 5244 5275 { (yyval.en) = new ExpressionNode( build_sizeOfexpr( (yyvsp[(2) - (2)].en) ) ); } 5245 5276 break; … … 5248 5279 5249 5280 /* Line 1806 of yacc.c */ 5250 #line 4 87"parser.yy"5281 #line 493 "parser.yy" 5251 5282 { (yyval.en) = new ExpressionNode( build_sizeOftype( (yyvsp[(3) - (4)].decl) ) ); } 5252 5283 break; … … 5255 5286 5256 5287 /* Line 1806 of yacc.c */ 5257 #line 4 89"parser.yy"5288 #line 495 "parser.yy" 5258 5289 { (yyval.en) = new ExpressionNode( build_alignOfexpr( (yyvsp[(2) - (2)].en) ) ); } 5259 5290 break; … … 5262 5293 5263 5294 /* Line 1806 of yacc.c */ 5264 #line 49 1"parser.yy"5295 #line 497 "parser.yy" 5265 5296 { (yyval.en) = new ExpressionNode( build_alignOftype( (yyvsp[(3) - (4)].decl) ) ); } 5266 5297 break; … … 5269 5300 5270 5301 /* Line 1806 of yacc.c */ 5271 #line 49 3"parser.yy"5302 #line 499 "parser.yy" 5272 5303 { (yyval.en) = new ExpressionNode( build_offsetOf( (yyvsp[(3) - (6)].decl), build_varref( (yyvsp[(5) - (6)].tok) ) ) ); } 5273 5304 break; … … 5276 5307 5277 5308 /* Line 1806 of yacc.c */ 5278 #line 495"parser.yy"5309 #line 501 "parser.yy" 5279 5310 { (yyval.en) = new ExpressionNode( build_attrexpr( build_varref( (yyvsp[(1) - (1)].tok) ), nullptr ) ); } 5280 5311 break; … … 5283 5314 5284 5315 /* Line 1806 of yacc.c */ 5285 #line 497"parser.yy"5316 #line 503 "parser.yy" 5286 5317 { (yyval.en) = new ExpressionNode( build_attrexpr( build_varref( (yyvsp[(1) - (4)].tok) ), (yyvsp[(3) - (4)].en) ) ); } 5287 5318 break; … … 5290 5321 5291 5322 /* Line 1806 of yacc.c */ 5292 #line 499"parser.yy"5323 #line 505 "parser.yy" 5293 5324 { (yyval.en) = new ExpressionNode( build_attrtype( build_varref( (yyvsp[(1) - (4)].tok) ), (yyvsp[(3) - (4)].decl) ) ); } 5294 5325 break; … … 5297 5328 5298 5329 /* Line 1806 of yacc.c */ 5299 #line 5 05"parser.yy"5330 #line 511 "parser.yy" 5300 5331 { (yyval.op) = OperKinds::PointTo; } 5301 5332 break; … … 5304 5335 5305 5336 /* Line 1806 of yacc.c */ 5306 #line 5 06"parser.yy"5337 #line 512 "parser.yy" 5307 5338 { (yyval.op) = OperKinds::AddressOf; } 5308 5339 break; … … 5311 5342 5312 5343 /* Line 1806 of yacc.c */ 5313 #line 51 2"parser.yy"5344 #line 518 "parser.yy" 5314 5345 { (yyval.op) = OperKinds::UnPlus; } 5315 5346 break; … … 5318 5349 5319 5350 /* Line 1806 of yacc.c */ 5320 #line 51 3"parser.yy"5351 #line 519 "parser.yy" 5321 5352 { (yyval.op) = OperKinds::UnMinus; } 5322 5353 break; … … 5325 5356 5326 5357 /* Line 1806 of yacc.c */ 5327 #line 5 14"parser.yy"5358 #line 520 "parser.yy" 5328 5359 { (yyval.op) = OperKinds::Neg; } 5329 5360 break; … … 5332 5363 5333 5364 /* Line 1806 of yacc.c */ 5334 #line 5 15"parser.yy"5365 #line 521 "parser.yy" 5335 5366 { (yyval.op) = OperKinds::BitNeg; } 5336 5367 break; … … 5339 5370 5340 5371 /* Line 1806 of yacc.c */ 5341 #line 52 1"parser.yy"5372 #line 527 "parser.yy" 5342 5373 { (yyval.en) = new ExpressionNode( build_cast( (yyvsp[(2) - (4)].decl), (yyvsp[(4) - (4)].en) ) ); } 5343 5374 break; … … 5346 5377 5347 5378 /* Line 1806 of yacc.c */ 5348 #line 5 29"parser.yy"5379 #line 535 "parser.yy" 5349 5380 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Mul, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5350 5381 break; … … 5353 5384 5354 5385 /* Line 1806 of yacc.c */ 5355 #line 53 1"parser.yy"5386 #line 537 "parser.yy" 5356 5387 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Div, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5357 5388 break; … … 5360 5391 5361 5392 /* Line 1806 of yacc.c */ 5362 #line 53 3"parser.yy"5393 #line 539 "parser.yy" 5363 5394 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Mod, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5364 5395 break; … … 5367 5398 5368 5399 /* Line 1806 of yacc.c */ 5369 #line 5 39"parser.yy"5400 #line 545 "parser.yy" 5370 5401 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Plus, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5371 5402 break; … … 5374 5405 5375 5406 /* Line 1806 of yacc.c */ 5376 #line 54 1"parser.yy"5407 #line 547 "parser.yy" 5377 5408 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Minus, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5378 5409 break; … … 5381 5412 5382 5413 /* Line 1806 of yacc.c */ 5383 #line 5 47"parser.yy"5414 #line 553 "parser.yy" 5384 5415 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::LShift, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5385 5416 break; … … 5388 5419 5389 5420 /* Line 1806 of yacc.c */ 5390 #line 5 49"parser.yy"5421 #line 555 "parser.yy" 5391 5422 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::RShift, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5392 5423 break; … … 5395 5426 5396 5427 /* Line 1806 of yacc.c */ 5397 #line 5 55"parser.yy"5428 #line 561 "parser.yy" 5398 5429 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::LThan, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5399 5430 break; … … 5402 5433 5403 5434 /* Line 1806 of yacc.c */ 5404 #line 5 57"parser.yy"5435 #line 563 "parser.yy" 5405 5436 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::GThan, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5406 5437 break; … … 5409 5440 5410 5441 /* Line 1806 of yacc.c */ 5411 #line 5 59"parser.yy"5442 #line 565 "parser.yy" 5412 5443 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::LEThan, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5413 5444 break; … … 5416 5447 5417 5448 /* Line 1806 of yacc.c */ 5418 #line 56 1"parser.yy"5449 #line 567 "parser.yy" 5419 5450 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::GEThan, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5420 5451 break; … … 5423 5454 5424 5455 /* Line 1806 of yacc.c */ 5425 #line 5 67"parser.yy"5456 #line 573 "parser.yy" 5426 5457 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Eq, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5427 5458 break; … … 5430 5461 5431 5462 /* Line 1806 of yacc.c */ 5432 #line 5 69"parser.yy"5463 #line 575 "parser.yy" 5433 5464 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Neq, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5434 5465 break; … … 5437 5468 5438 5469 /* Line 1806 of yacc.c */ 5439 #line 5 75"parser.yy"5470 #line 581 "parser.yy" 5440 5471 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::BitAnd, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5441 5472 break; … … 5444 5475 5445 5476 /* Line 1806 of yacc.c */ 5446 #line 58 1"parser.yy"5477 #line 587 "parser.yy" 5447 5478 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Xor, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5448 5479 break; … … 5451 5482 5452 5483 /* Line 1806 of yacc.c */ 5453 #line 5 87"parser.yy"5484 #line 593 "parser.yy" 5454 5485 { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::BitOr, (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5455 5486 break; … … 5458 5489 5459 5490 /* Line 1806 of yacc.c */ 5460 #line 59 3"parser.yy"5491 #line 599 "parser.yy" 5461 5492 { (yyval.en) = new ExpressionNode( build_and_or( (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en), true ) ); } 5462 5493 break; … … 5465 5496 5466 5497 /* Line 1806 of yacc.c */ 5467 #line 599"parser.yy"5498 #line 605 "parser.yy" 5468 5499 { (yyval.en) = new ExpressionNode( build_and_or( (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en), false ) ); } 5469 5500 break; … … 5472 5503 5473 5504 /* Line 1806 of yacc.c */ 5474 #line 6 05"parser.yy"5505 #line 611 "parser.yy" 5475 5506 { (yyval.en) = new ExpressionNode( build_cond( (yyvsp[(1) - (5)].en), (yyvsp[(3) - (5)].en), (yyvsp[(5) - (5)].en) ) ); } 5476 5507 break; … … 5479 5510 5480 5511 /* Line 1806 of yacc.c */ 5481 #line 6 08"parser.yy"5512 #line 614 "parser.yy" 5482 5513 { (yyval.en) = new ExpressionNode( build_cond( (yyvsp[(1) - (4)].en), (yyvsp[(1) - (4)].en), (yyvsp[(4) - (4)].en) ) ); } 5483 5514 break; … … 5486 5517 5487 5518 /* Line 1806 of yacc.c */ 5488 #line 62 1"parser.yy"5519 #line 627 "parser.yy" 5489 5520 { (yyval.en) = new ExpressionNode( build_binary_ptr( (yyvsp[(2) - (3)].op), (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5490 5521 break; … … 5493 5524 5494 5525 /* Line 1806 of yacc.c */ 5495 #line 6 28"parser.yy"5526 #line 634 "parser.yy" 5496 5527 { (yyval.en) = nullptr; } 5497 5528 break; … … 5500 5531 5501 5532 /* Line 1806 of yacc.c */ 5502 #line 63 3"parser.yy"5533 #line 639 "parser.yy" 5503 5534 { (yyval.op) = OperKinds::Assign; } 5504 5535 break; … … 5507 5538 5508 5539 /* Line 1806 of yacc.c */ 5509 #line 6 34"parser.yy"5540 #line 640 "parser.yy" 5510 5541 { (yyval.op) = OperKinds::AtAssn; } 5511 5542 break; … … 5514 5545 5515 5546 /* Line 1806 of yacc.c */ 5516 #line 6 35"parser.yy"5547 #line 641 "parser.yy" 5517 5548 { (yyval.op) = OperKinds::MulAssn; } 5518 5549 break; … … 5521 5552 5522 5553 /* Line 1806 of yacc.c */ 5523 #line 6 36"parser.yy"5554 #line 642 "parser.yy" 5524 5555 { (yyval.op) = OperKinds::DivAssn; } 5525 5556 break; … … 5528 5559 5529 5560 /* Line 1806 of yacc.c */ 5530 #line 6 37"parser.yy"5561 #line 643 "parser.yy" 5531 5562 { (yyval.op) = OperKinds::ModAssn; } 5532 5563 break; … … 5535 5566 5536 5567 /* Line 1806 of yacc.c */ 5537 #line 6 38"parser.yy"5568 #line 644 "parser.yy" 5538 5569 { (yyval.op) = OperKinds::PlusAssn; } 5539 5570 break; … … 5542 5573 5543 5574 /* Line 1806 of yacc.c */ 5544 #line 6 39"parser.yy"5575 #line 645 "parser.yy" 5545 5576 { (yyval.op) = OperKinds::MinusAssn; } 5546 5577 break; … … 5549 5580 5550 5581 /* Line 1806 of yacc.c */ 5551 #line 64 0"parser.yy"5582 #line 646 "parser.yy" 5552 5583 { (yyval.op) = OperKinds::LSAssn; } 5553 5584 break; … … 5556 5587 5557 5588 /* Line 1806 of yacc.c */ 5558 #line 64 1"parser.yy"5589 #line 647 "parser.yy" 5559 5590 { (yyval.op) = OperKinds::RSAssn; } 5560 5591 break; … … 5563 5594 5564 5595 /* Line 1806 of yacc.c */ 5565 #line 64 2"parser.yy"5596 #line 648 "parser.yy" 5566 5597 { (yyval.op) = OperKinds::AndAssn; } 5567 5598 break; … … 5570 5601 5571 5602 /* Line 1806 of yacc.c */ 5572 #line 64 3"parser.yy"5603 #line 649 "parser.yy" 5573 5604 { (yyval.op) = OperKinds::ERAssn; } 5574 5605 break; … … 5577 5608 5578 5609 /* Line 1806 of yacc.c */ 5579 #line 6 44"parser.yy"5610 #line 650 "parser.yy" 5580 5611 { (yyval.op) = OperKinds::OrAssn; } 5581 5612 break; … … 5584 5615 5585 5616 /* Line 1806 of yacc.c */ 5586 #line 6 55"parser.yy"5617 #line 661 "parser.yy" 5587 5618 { (yyval.en) = new ExpressionNode( build_tuple( (ExpressionNode *)(new ExpressionNode( nullptr ) )->set_last( (yyvsp[(4) - (6)].en) ) ) ); } 5588 5619 break; … … 5591 5622 5592 5623 /* Line 1806 of yacc.c */ 5593 #line 6 57"parser.yy"5624 #line 663 "parser.yy" 5594 5625 { (yyval.en) = new ExpressionNode( build_tuple( (ExpressionNode *)(yyvsp[(3) - (7)].en)->set_last( (yyvsp[(5) - (7)].en) ) ) ); } 5595 5626 break; … … 5598 5629 5599 5630 /* Line 1806 of yacc.c */ 5600 #line 66 3"parser.yy"5631 #line 669 "parser.yy" 5601 5632 { (yyval.en) = (ExpressionNode *)(yyvsp[(1) - (3)].en)->set_last( (yyvsp[(3) - (3)].en) ); } 5602 5633 break; … … 5605 5636 5606 5637 /* Line 1806 of yacc.c */ 5607 #line 6 69"parser.yy"5638 #line 675 "parser.yy" 5608 5639 { (yyval.en) = new ExpressionNode( build_comma( (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5609 5640 break; … … 5612 5643 5613 5644 /* Line 1806 of yacc.c */ 5614 #line 6 74"parser.yy"5645 #line 680 "parser.yy" 5615 5646 { (yyval.en) = 0; } 5616 5647 break; … … 5619 5650 5620 5651 /* Line 1806 of yacc.c */ 5621 #line 68 3"parser.yy"5652 #line 689 "parser.yy" 5622 5653 { (yyval.sn) = (yyvsp[(1) - (1)].sn); } 5623 5654 break; … … 5626 5657 5627 5658 /* Line 1806 of yacc.c */ 5628 #line 69 0"parser.yy"5659 #line 696 "parser.yy" 5629 5660 { 5630 5661 Token fn; … … 5637 5668 5638 5669 /* Line 1806 of yacc.c */ 5639 #line 70 0"parser.yy"5670 #line 706 "parser.yy" 5640 5671 { 5641 5672 (yyval.sn) = (yyvsp[(4) - (4)].sn)->add_label( (yyvsp[(1) - (4)].tok) ); … … 5646 5677 5647 5678 /* Line 1806 of yacc.c */ 5648 #line 7 07"parser.yy"5679 #line 713 "parser.yy" 5649 5680 { (yyval.sn) = new StatementNode( build_compound( (StatementNode *)0 ) ); } 5650 5681 break; … … 5653 5684 5654 5685 /* Line 1806 of yacc.c */ 5655 #line 7 14"parser.yy"5686 #line 720 "parser.yy" 5656 5687 { (yyval.sn) = new StatementNode( build_compound( (yyvsp[(5) - (7)].sn) ) ); } 5657 5688 break; … … 5660 5691 5661 5692 /* Line 1806 of yacc.c */ 5662 #line 72 0"parser.yy"5693 #line 726 "parser.yy" 5663 5694 { if ( (yyvsp[(1) - (3)].sn) != 0 ) { (yyvsp[(1) - (3)].sn)->set_last( (yyvsp[(3) - (3)].sn) ); (yyval.sn) = (yyvsp[(1) - (3)].sn); } } 5664 5695 break; … … 5667 5698 5668 5699 /* Line 1806 of yacc.c */ 5669 #line 7 25"parser.yy"5700 #line 731 "parser.yy" 5670 5701 { (yyval.sn) = new StatementNode( (yyvsp[(1) - (1)].decl) ); } 5671 5702 break; … … 5674 5705 5675 5706 /* Line 1806 of yacc.c */ 5676 #line 7 27"parser.yy"5707 #line 733 "parser.yy" 5677 5708 { // mark all fields in list 5678 5709 for ( DeclarationNode *iter = (yyvsp[(2) - (2)].decl); iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) … … 5685 5716 5686 5717 /* Line 1806 of yacc.c */ 5687 #line 73 3"parser.yy"5718 #line 739 "parser.yy" 5688 5719 { (yyval.sn) = new StatementNode( (yyvsp[(1) - (1)].decl) ); } 5689 5720 break; … … 5692 5723 5693 5724 /* Line 1806 of yacc.c */ 5694 #line 74 0"parser.yy"5725 #line 746 "parser.yy" 5695 5726 { if ( (yyvsp[(1) - (2)].sn) != 0 ) { (yyvsp[(1) - (2)].sn)->set_last( (yyvsp[(2) - (2)].sn) ); (yyval.sn) = (yyvsp[(1) - (2)].sn); } } 5696 5727 break; … … 5699 5730 5700 5731 /* Line 1806 of yacc.c */ 5701 #line 7 45"parser.yy"5732 #line 751 "parser.yy" 5702 5733 { (yyval.sn) = new StatementNode( build_expr( (yyvsp[(1) - (2)].en) ) ); } 5703 5734 break; … … 5706 5737 5707 5738 /* Line 1806 of yacc.c */ 5708 #line 75 1"parser.yy"5739 #line 757 "parser.yy" 5709 5740 { (yyval.sn) = new StatementNode( build_if( (yyvsp[(3) - (5)].en), (yyvsp[(5) - (5)].sn), nullptr ) ); } 5710 5741 break; … … 5713 5744 5714 5745 /* Line 1806 of yacc.c */ 5715 #line 75 3"parser.yy"5746 #line 759 "parser.yy" 5716 5747 { (yyval.sn) = new StatementNode( build_if( (yyvsp[(3) - (7)].en), (yyvsp[(5) - (7)].sn), (yyvsp[(7) - (7)].sn) ) ); } 5717 5748 break; … … 5720 5751 5721 5752 /* Line 1806 of yacc.c */ 5722 #line 7 55"parser.yy"5753 #line 761 "parser.yy" 5723 5754 { (yyval.sn) = new StatementNode( build_switch( (yyvsp[(3) - (5)].en), (yyvsp[(5) - (5)].sn) ) ); } 5724 5755 break; … … 5727 5758 5728 5759 /* Line 1806 of yacc.c */ 5729 #line 7 57"parser.yy"5760 #line 763 "parser.yy" 5730 5761 { 5731 5762 StatementNode *sw = new StatementNode( build_switch( (yyvsp[(3) - (9)].en), (yyvsp[(8) - (9)].sn) ) ); … … 5742 5773 5743 5774 /* Line 1806 of yacc.c */ 5744 #line 7 67"parser.yy"5775 #line 773 "parser.yy" 5745 5776 { (yyval.sn) = new StatementNode( build_switch( (yyvsp[(3) - (5)].en), (yyvsp[(5) - (5)].sn) ) ); } 5746 5777 break; … … 5749 5780 5750 5781 /* Line 1806 of yacc.c */ 5751 #line 7 69"parser.yy"5782 #line 775 "parser.yy" 5752 5783 { 5753 5784 StatementNode *sw = new StatementNode( build_switch( (yyvsp[(3) - (9)].en), (yyvsp[(8) - (9)].sn) ) ); … … 5759 5790 5760 5791 /* Line 1806 of yacc.c */ 5761 #line 7 79"parser.yy"5792 #line 785 "parser.yy" 5762 5793 { (yyval.en) = (yyvsp[(1) - (1)].en); } 5763 5794 break; … … 5766 5797 5767 5798 /* Line 1806 of yacc.c */ 5768 #line 78 1"parser.yy"5799 #line 787 "parser.yy" 5769 5800 { (yyval.en) = new ExpressionNode( build_range( (yyvsp[(1) - (3)].en), (yyvsp[(3) - (3)].en) ) ); } 5770 5801 break; … … 5773 5804 5774 5805 /* Line 1806 of yacc.c */ 5775 #line 7 86"parser.yy"5806 #line 792 "parser.yy" 5776 5807 { (yyval.sn) = new StatementNode( build_case( (yyvsp[(1) - (1)].en) ) ); } 5777 5808 break; … … 5780 5811 5781 5812 /* Line 1806 of yacc.c */ 5782 #line 7 88"parser.yy"5813 #line 794 "parser.yy" 5783 5814 { (yyval.sn) = (StatementNode *)((yyvsp[(1) - (3)].sn)->set_last( new StatementNode( build_case( (yyvsp[(3) - (3)].en) ) ) ) ); } 5784 5815 break; … … 5787 5818 5788 5819 /* Line 1806 of yacc.c */ 5789 #line 79 2"parser.yy"5820 #line 798 "parser.yy" 5790 5821 { (yyval.sn) = (yyvsp[(2) - (3)].sn); } 5791 5822 break; … … 5794 5825 5795 5826 /* Line 1806 of yacc.c */ 5796 #line 79 3"parser.yy"5827 #line 799 "parser.yy" 5797 5828 { (yyval.sn) = new StatementNode( build_default() ); } 5798 5829 break; … … 5801 5832 5802 5833 /* Line 1806 of yacc.c */ 5803 #line 799"parser.yy"5834 #line 805 "parser.yy" 5804 5835 { (yyval.sn) = (StatementNode *)( (yyvsp[(1) - (2)].sn)->set_last( (yyvsp[(2) - (2)].sn) )); } 5805 5836 break; … … 5808 5839 5809 5840 /* Line 1806 of yacc.c */ 5810 #line 80 3"parser.yy"5841 #line 809 "parser.yy" 5811 5842 { (yyval.sn) = (yyvsp[(1) - (2)].sn)->append_last_case( new StatementNode( build_compound( (yyvsp[(2) - (2)].sn) ) ) ); } 5812 5843 break; … … 5815 5846 5816 5847 /* Line 1806 of yacc.c */ 5817 #line 8 08"parser.yy"5848 #line 814 "parser.yy" 5818 5849 { (yyval.sn) = 0; } 5819 5850 break; … … 5822 5853 5823 5854 /* Line 1806 of yacc.c */ 5824 #line 8 14"parser.yy"5855 #line 820 "parser.yy" 5825 5856 { (yyval.sn) = (yyvsp[(1) - (2)].sn)->append_last_case( new StatementNode( build_compound( (yyvsp[(2) - (2)].sn) ) ) ); } 5826 5857 break; … … 5829 5860 5830 5861 /* Line 1806 of yacc.c */ 5831 #line 8 16"parser.yy"5862 #line 822 "parser.yy" 5832 5863 { (yyval.sn) = (StatementNode *)( (yyvsp[(1) - (3)].sn)->set_last( (yyvsp[(2) - (3)].sn)->append_last_case( new StatementNode( build_compound( (yyvsp[(3) - (3)].sn) ) ) ) ) ); } 5833 5864 break; … … 5836 5867 5837 5868 /* Line 1806 of yacc.c */ 5838 #line 82 1"parser.yy"5869 #line 827 "parser.yy" 5839 5870 { (yyval.sn) = 0; } 5840 5871 break; … … 5843 5874 5844 5875 /* Line 1806 of yacc.c */ 5845 #line 8 27"parser.yy"5876 #line 833 "parser.yy" 5846 5877 { (yyval.sn) = (yyvsp[(1) - (2)].sn)->append_last_case( (yyvsp[(2) - (2)].sn) ); } 5847 5878 break; … … 5850 5881 5851 5882 /* Line 1806 of yacc.c */ 5852 #line 8 29"parser.yy"5883 #line 835 "parser.yy" 5853 5884 { (yyval.sn) = (yyvsp[(1) - (3)].sn)->append_last_case( new StatementNode( build_compound( (StatementNode *)(yyvsp[(2) - (3)].sn)->set_last( (yyvsp[(3) - (3)].sn) ) ) ) ); } 5854 5885 break; … … 5857 5888 5858 5889 /* Line 1806 of yacc.c */ 5859 #line 83 1"parser.yy"5890 #line 837 "parser.yy" 5860 5891 { (yyval.sn) = (StatementNode *)( (yyvsp[(1) - (3)].sn)->set_last( (yyvsp[(2) - (3)].sn)->append_last_case( (yyvsp[(3) - (3)].sn) ))); } 5861 5892 break; … … 5864 5895 5865 5896 /* Line 1806 of yacc.c */ 5866 #line 83 3"parser.yy"5897 #line 839 "parser.yy" 5867 5898 { (yyval.sn) = (StatementNode *)( (yyvsp[(1) - (4)].sn)->set_last( (yyvsp[(2) - (4)].sn)->append_last_case( new StatementNode( build_compound( (StatementNode *)(yyvsp[(3) - (4)].sn)->set_last( (yyvsp[(4) - (4)].sn) ) ) ) ) ) ); } 5868 5899 break; … … 5871 5902 5872 5903 /* Line 1806 of yacc.c */ 5873 #line 8 38"parser.yy"5904 #line 844 "parser.yy" 5874 5905 { (yyval.sn) = new StatementNode( build_branch( BranchStmt::Break ) ); } 5875 5906 break; … … 5878 5909 5879 5910 /* Line 1806 of yacc.c */ 5880 #line 8 44"parser.yy"5911 #line 850 "parser.yy" 5881 5912 { (yyval.sn) = 0; } 5882 5913 break; … … 5885 5916 5886 5917 /* Line 1806 of yacc.c */ 5887 #line 8 46"parser.yy"5918 #line 852 "parser.yy" 5888 5919 { (yyval.sn) = 0; } 5889 5920 break; … … 5892 5923 5893 5924 /* Line 1806 of yacc.c */ 5894 #line 85 1"parser.yy"5925 #line 857 "parser.yy" 5895 5926 { (yyval.sn) = new StatementNode( build_while( (yyvsp[(3) - (5)].en), (yyvsp[(5) - (5)].sn) ) ); } 5896 5927 break; … … 5899 5930 5900 5931 /* Line 1806 of yacc.c */ 5901 #line 85 3"parser.yy"5932 #line 859 "parser.yy" 5902 5933 { (yyval.sn) = new StatementNode( build_while( (yyvsp[(5) - (7)].en), (yyvsp[(2) - (7)].sn), true ) ); } 5903 5934 break; … … 5906 5937 5907 5938 /* Line 1806 of yacc.c */ 5908 #line 8 55"parser.yy"5939 #line 861 "parser.yy" 5909 5940 { (yyval.sn) = new StatementNode( build_for( (yyvsp[(4) - (6)].fctl), (yyvsp[(6) - (6)].sn) ) ); } 5910 5941 break; … … 5913 5944 5914 5945 /* Line 1806 of yacc.c */ 5915 #line 86 0"parser.yy"5946 #line 866 "parser.yy" 5916 5947 { (yyval.fctl) = new ForCtl( (yyvsp[(1) - (6)].en), (yyvsp[(4) - (6)].en), (yyvsp[(6) - (6)].en) ); } 5917 5948 break; … … 5920 5951 5921 5952 /* Line 1806 of yacc.c */ 5922 #line 86 2"parser.yy"5953 #line 868 "parser.yy" 5923 5954 { (yyval.fctl) = new ForCtl( (yyvsp[(1) - (4)].decl), (yyvsp[(2) - (4)].en), (yyvsp[(4) - (4)].en) ); } 5924 5955 break; … … 5927 5958 5928 5959 /* Line 1806 of yacc.c */ 5929 #line 8 67"parser.yy"5960 #line 873 "parser.yy" 5930 5961 { (yyval.sn) = new StatementNode( build_branch( (yyvsp[(2) - (3)].tok), BranchStmt::Goto ) ); } 5931 5962 break; … … 5934 5965 5935 5966 /* Line 1806 of yacc.c */ 5936 #line 87 1"parser.yy"5967 #line 877 "parser.yy" 5937 5968 { (yyval.sn) = new StatementNode( build_computedgoto( (yyvsp[(3) - (4)].en) ) ); } 5938 5969 break; … … 5941 5972 5942 5973 /* Line 1806 of yacc.c */ 5943 #line 8 74"parser.yy"5974 #line 880 "parser.yy" 5944 5975 { (yyval.sn) = new StatementNode( build_branch( BranchStmt::Continue ) ); } 5945 5976 break; … … 5948 5979 5949 5980 /* Line 1806 of yacc.c */ 5950 #line 8 78"parser.yy"5981 #line 884 "parser.yy" 5951 5982 { (yyval.sn) = new StatementNode( build_branch( (yyvsp[(2) - (3)].tok), BranchStmt::Continue ) ); } 5952 5983 break; … … 5955 5986 5956 5987 /* Line 1806 of yacc.c */ 5957 #line 88 1"parser.yy"5988 #line 887 "parser.yy" 5958 5989 { (yyval.sn) = new StatementNode( build_branch( BranchStmt::Break ) ); } 5959 5990 break; … … 5962 5993 5963 5994 /* Line 1806 of yacc.c */ 5964 #line 8 85"parser.yy"5995 #line 891 "parser.yy" 5965 5996 { (yyval.sn) = new StatementNode( build_branch( (yyvsp[(2) - (3)].tok), BranchStmt::Break ) ); } 5966 5997 break; … … 5969 6000 5970 6001 /* Line 1806 of yacc.c */ 5971 #line 8 87"parser.yy"6002 #line 893 "parser.yy" 5972 6003 { (yyval.sn) = new StatementNode( build_return( (yyvsp[(2) - (3)].en) ) ); } 5973 6004 break; … … 5976 6007 5977 6008 /* Line 1806 of yacc.c */ 5978 #line 8 89"parser.yy"6009 #line 895 "parser.yy" 5979 6010 { (yyval.sn) = new StatementNode( build_throw( (yyvsp[(2) - (3)].en) ) ); } 5980 6011 break; … … 5983 6014 5984 6015 /* Line 1806 of yacc.c */ 5985 #line 89 1"parser.yy"6016 #line 897 "parser.yy" 5986 6017 { (yyval.sn) = new StatementNode( build_throw( (yyvsp[(2) - (3)].en) ) ); } 5987 6018 break; … … 5990 6021 5991 6022 /* Line 1806 of yacc.c */ 5992 #line 89 3"parser.yy"6023 #line 899 "parser.yy" 5993 6024 { (yyval.sn) = new StatementNode( build_throw( (yyvsp[(2) - (5)].en) ) ); } 5994 6025 break; … … 5997 6028 5998 6029 /* Line 1806 of yacc.c */ 5999 #line 898"parser.yy"6030 #line 904 "parser.yy" 6000 6031 { (yyval.sn) = new StatementNode( build_try( (yyvsp[(2) - (3)].sn), (yyvsp[(3) - (3)].sn), 0 ) ); } 6001 6032 break; … … 6004 6035 6005 6036 /* Line 1806 of yacc.c */ 6006 #line 90 0"parser.yy"6037 #line 906 "parser.yy" 6007 6038 { (yyval.sn) = new StatementNode( build_try( (yyvsp[(2) - (3)].sn), 0, (yyvsp[(3) - (3)].sn) ) ); } 6008 6039 break; … … 6011 6042 6012 6043 /* Line 1806 of yacc.c */ 6013 #line 90 2"parser.yy"6044 #line 908 "parser.yy" 6014 6045 { (yyval.sn) = new StatementNode( build_try( (yyvsp[(2) - (4)].sn), (yyvsp[(3) - (4)].sn), (yyvsp[(4) - (4)].sn) ) ); } 6015 6046 break; … … 6018 6049 6019 6050 /* Line 1806 of yacc.c */ 6020 #line 9 09"parser.yy"6051 #line 915 "parser.yy" 6021 6052 { (yyval.sn) = new StatementNode( build_catch( 0, (yyvsp[(5) - (5)].sn), true ) ); } 6022 6053 break; … … 6025 6056 6026 6057 /* Line 1806 of yacc.c */ 6027 #line 91 1"parser.yy"6058 #line 917 "parser.yy" 6028 6059 { (yyval.sn) = (StatementNode *)(yyvsp[(1) - (6)].sn)->set_last( new StatementNode( build_catch( 0, (yyvsp[(6) - (6)].sn), true ) ) ); } 6029 6060 break; … … 6032 6063 6033 6064 /* Line 1806 of yacc.c */ 6034 #line 91 3"parser.yy"6065 #line 919 "parser.yy" 6035 6066 { (yyval.sn) = new StatementNode( build_catch( 0, (yyvsp[(5) - (5)].sn), true ) ); } 6036 6067 break; … … 6039 6070 6040 6071 /* Line 1806 of yacc.c */ 6041 #line 9 15"parser.yy"6072 #line 921 "parser.yy" 6042 6073 { (yyval.sn) = (StatementNode *)(yyvsp[(1) - (6)].sn)->set_last( new StatementNode( build_catch( 0, (yyvsp[(6) - (6)].sn), true ) ) ); } 6043 6074 break; … … 6046 6077 6047 6078 /* Line 1806 of yacc.c */ 6048 #line 92 0"parser.yy"6079 #line 926 "parser.yy" 6049 6080 { (yyval.sn) = new StatementNode( build_catch( (yyvsp[(5) - (9)].decl), (yyvsp[(8) - (9)].sn) ) ); } 6050 6081 break; … … 6053 6084 6054 6085 /* Line 1806 of yacc.c */ 6055 #line 92 2"parser.yy"6086 #line 928 "parser.yy" 6056 6087 { (yyval.sn) = (StatementNode *)(yyvsp[(1) - (10)].sn)->set_last( new StatementNode( build_catch( (yyvsp[(6) - (10)].decl), (yyvsp[(9) - (10)].sn) ) ) ); } 6057 6088 break; … … 6060 6091 6061 6092 /* Line 1806 of yacc.c */ 6062 #line 9 24"parser.yy"6093 #line 930 "parser.yy" 6063 6094 { (yyval.sn) = new StatementNode( build_catch( (yyvsp[(5) - (9)].decl), (yyvsp[(8) - (9)].sn) ) ); } 6064 6095 break; … … 6067 6098 6068 6099 /* Line 1806 of yacc.c */ 6069 #line 9 26"parser.yy"6100 #line 932 "parser.yy" 6070 6101 { (yyval.sn) = (StatementNode *)(yyvsp[(1) - (10)].sn)->set_last( new StatementNode( build_catch( (yyvsp[(6) - (10)].decl), (yyvsp[(9) - (10)].sn) ) ) ); } 6071 6102 break; … … 6074 6105 6075 6106 /* Line 1806 of yacc.c */ 6076 #line 93 1"parser.yy"6107 #line 937 "parser.yy" 6077 6108 { 6078 6109 (yyval.sn) = new StatementNode( build_finally( (yyvsp[(2) - (2)].sn) ) ); … … 6083 6114 6084 6115 /* Line 1806 of yacc.c */ 6085 #line 9 44"parser.yy"6116 #line 950 "parser.yy" 6086 6117 { 6087 6118 typedefTable.addToEnclosingScope( TypedefTable::ID ); … … 6093 6124 6094 6125 /* Line 1806 of yacc.c */ 6095 #line 9 49"parser.yy"6126 #line 955 "parser.yy" 6096 6127 { (yyval.decl) = (yyvsp[(2) - (2)].decl)->addType( (yyvsp[(1) - (2)].decl) ); } 6097 6128 break; … … 6100 6131 6101 6132 /* Line 1806 of yacc.c */ 6102 #line 95 1"parser.yy"6133 #line 957 "parser.yy" 6103 6134 { 6104 6135 typedefTable.addToEnclosingScope( TypedefTable::ID ); … … 6110 6141 6111 6142 /* Line 1806 of yacc.c */ 6112 #line 96 0"parser.yy"6143 #line 966 "parser.yy" 6113 6144 { (yyval.sn) = new StatementNode( build_asmstmt( (yyvsp[(2) - (6)].flag), (yyvsp[(4) - (6)].constant), 0 ) ); } 6114 6145 break; … … 6117 6148 6118 6149 /* Line 1806 of yacc.c */ 6119 #line 96 2"parser.yy"6150 #line 968 "parser.yy" 6120 6151 { (yyval.sn) = new StatementNode( build_asmstmt( (yyvsp[(2) - (8)].flag), (yyvsp[(4) - (8)].constant), (yyvsp[(6) - (8)].en) ) ); } 6121 6152 break; … … 6124 6155 6125 6156 /* Line 1806 of yacc.c */ 6126 #line 9 64"parser.yy"6157 #line 970 "parser.yy" 6127 6158 { (yyval.sn) = new StatementNode( build_asmstmt( (yyvsp[(2) - (10)].flag), (yyvsp[(4) - (10)].constant), (yyvsp[(6) - (10)].en), (yyvsp[(8) - (10)].en) ) ); } 6128 6159 break; … … 6131 6162 6132 6163 /* Line 1806 of yacc.c */ 6133 #line 9 66"parser.yy"6164 #line 972 "parser.yy" 6134 6165 { (yyval.sn) = new StatementNode( build_asmstmt( (yyvsp[(2) - (12)].flag), (yyvsp[(4) - (12)].constant), (yyvsp[(6) - (12)].en), (yyvsp[(8) - (12)].en), (yyvsp[(10) - (12)].en) ) ); } 6135 6166 break; … … 6138 6169 6139 6170 /* Line 1806 of yacc.c */ 6140 #line 9 68"parser.yy"6171 #line 974 "parser.yy" 6141 6172 { (yyval.sn) = new StatementNode( build_asmstmt( (yyvsp[(2) - (14)].flag), (yyvsp[(5) - (14)].constant), 0, (yyvsp[(8) - (14)].en), (yyvsp[(10) - (14)].en), (yyvsp[(12) - (14)].label) ) ); } 6142 6173 break; … … 6145 6176 6146 6177 /* Line 1806 of yacc.c */ 6147 #line 97 3"parser.yy"6178 #line 979 "parser.yy" 6148 6179 { (yyval.flag) = false; } 6149 6180 break; … … 6152 6183 6153 6184 /* Line 1806 of yacc.c */ 6154 #line 9 75"parser.yy"6185 #line 981 "parser.yy" 6155 6186 { (yyval.flag) = true; } 6156 6187 break; … … 6159 6190 6160 6191 /* Line 1806 of yacc.c */ 6161 #line 98 0"parser.yy"6192 #line 986 "parser.yy" 6162 6193 { (yyval.en) = 0; } 6163 6194 break; … … 6166 6197 6167 6198 /* Line 1806 of yacc.c */ 6168 #line 9 87"parser.yy"6199 #line 993 "parser.yy" 6169 6200 { (yyval.en) = (ExpressionNode *)(yyvsp[(1) - (3)].en)->set_last( (yyvsp[(3) - (3)].en) ); } 6170 6201 break; … … 6173 6204 6174 6205 /* Line 1806 of yacc.c */ 6175 #line 99 2"parser.yy"6206 #line 998 "parser.yy" 6176 6207 { (yyval.en) = new ExpressionNode( build_asmexpr( 0, (yyvsp[(1) - (4)].constant), (yyvsp[(3) - (4)].en) ) ); } 6177 6208 break; … … 6180 6211 6181 6212 /* Line 1806 of yacc.c */ 6182 #line 994"parser.yy"6213 #line 1000 "parser.yy" 6183 6214 { (yyval.en) = new ExpressionNode( build_asmexpr( (yyvsp[(2) - (7)].en), (yyvsp[(4) - (7)].constant), (yyvsp[(6) - (7)].en) ) ); } 6184 6215 break; … … 6187 6218 6188 6219 /* Line 1806 of yacc.c */ 6189 #line 999"parser.yy"6220 #line 1005 "parser.yy" 6190 6221 { (yyval.en) = 0; } 6191 6222 break; … … 6194 6225 6195 6226 /* Line 1806 of yacc.c */ 6196 #line 100 1"parser.yy"6227 #line 1007 "parser.yy" 6197 6228 { (yyval.en) = new ExpressionNode( (yyvsp[(1) - (1)].constant) ); } 6198 6229 break; … … 6201 6232 6202 6233 /* Line 1806 of yacc.c */ 6203 #line 100 3"parser.yy"6234 #line 1009 "parser.yy" 6204 6235 { (yyval.en) = (ExpressionNode *)(yyvsp[(1) - (3)].en)->set_last( new ExpressionNode( (yyvsp[(3) - (3)].constant) ) ); } 6205 6236 break; … … 6208 6239 6209 6240 /* Line 1806 of yacc.c */ 6210 #line 10 08"parser.yy"6241 #line 1014 "parser.yy" 6211 6242 { 6212 6243 (yyval.label) = new LabelNode(); (yyval.label)->labels.push_back( *(yyvsp[(1) - (1)].tok) ); … … 6218 6249 6219 6250 /* Line 1806 of yacc.c */ 6220 #line 101 3"parser.yy"6251 #line 1019 "parser.yy" 6221 6252 { 6222 6253 (yyval.label) = (yyvsp[(1) - (3)].label); (yyvsp[(1) - (3)].label)->labels.push_back( *(yyvsp[(3) - (3)].tok) ); … … 6228 6259 6229 6260 /* Line 1806 of yacc.c */ 6230 #line 102 3"parser.yy"6261 #line 1029 "parser.yy" 6231 6262 { (yyval.decl) = 0; } 6232 6263 break; … … 6235 6266 6236 6267 /* Line 1806 of yacc.c */ 6237 #line 103 0"parser.yy"6268 #line 1036 "parser.yy" 6238 6269 { (yyval.decl) = (yyvsp[(1) - (3)].decl)->appendList( (yyvsp[(3) - (3)].decl) ); } 6239 6270 break; … … 6242 6273 6243 6274 /* Line 1806 of yacc.c */ 6244 #line 10 35"parser.yy"6275 #line 1041 "parser.yy" 6245 6276 { (yyval.decl) = 0; } 6246 6277 break; … … 6249 6280 6250 6281 /* Line 1806 of yacc.c */ 6251 #line 104 2"parser.yy"6282 #line 1048 "parser.yy" 6252 6283 { (yyval.decl) = (yyvsp[(1) - (3)].decl)->appendList( (yyvsp[(3) - (3)].decl) ); } 6253 6284 break; … … 6256 6287 6257 6288 /* Line 1806 of yacc.c */ 6258 #line 10 56"parser.yy"6289 #line 1062 "parser.yy" 6259 6290 {} 6260 6291 break; … … 6263 6294 6264 6295 /* Line 1806 of yacc.c */ 6265 #line 10 57"parser.yy"6296 #line 1063 "parser.yy" 6266 6297 {} 6267 6298 break; … … 6270 6301 6271 6302 /* Line 1806 of yacc.c */ 6272 #line 10 86"parser.yy"6303 #line 1092 "parser.yy" 6273 6304 { 6274 6305 typedefTable.addToEnclosingScope( TypedefTable::ID ); … … 6280 6311 6281 6312 /* Line 1806 of yacc.c */ 6282 #line 109 3"parser.yy"6313 #line 1099 "parser.yy" 6283 6314 { 6284 6315 typedefTable.addToEnclosingScope( TypedefTable::ID ); … … 6290 6321 6291 6322 /* Line 1806 of yacc.c */ 6292 #line 1 098"parser.yy"6323 #line 1104 "parser.yy" 6293 6324 { 6294 6325 typedefTable.addToEnclosingScope( *(yyvsp[(5) - (6)].tok), TypedefTable::ID ); … … 6300 6331 6301 6332 /* Line 1806 of yacc.c */ 6302 #line 11 08"parser.yy"6333 #line 1114 "parser.yy" 6303 6334 { 6304 6335 typedefTable.setNextIdentifier( *(yyvsp[(2) - (3)].tok) ); … … 6310 6341 6311 6342 /* Line 1806 of yacc.c */ 6312 #line 111 3"parser.yy"6343 #line 1119 "parser.yy" 6313 6344 { 6314 6345 typedefTable.setNextIdentifier( *(yyvsp[(2) - (3)].tok) ); … … 6320 6351 6321 6352 /* Line 1806 of yacc.c */ 6322 #line 11 18"parser.yy"6353 #line 1124 "parser.yy" 6323 6354 { 6324 6355 typedefTable.setNextIdentifier( *(yyvsp[(3) - (4)].tok) ); … … 6330 6361 6331 6362 /* Line 1806 of yacc.c */ 6332 #line 11 26"parser.yy"6363 #line 1132 "parser.yy" 6333 6364 { 6334 6365 typedefTable.addToEnclosingScope( TypedefTable::ID ); … … 6340 6371 6341 6372 /* Line 1806 of yacc.c */ 6342 #line 113 1"parser.yy"6373 #line 1137 "parser.yy" 6343 6374 { 6344 6375 typedefTable.addToEnclosingScope( TypedefTable::ID ); … … 6350 6381 6351 6382 /* Line 1806 of yacc.c */ 6352 #line 11 36"parser.yy"6383 #line 1142 "parser.yy" 6353 6384 { 6354 6385 typedefTable.addToEnclosingScope( TypedefTable::ID ); … … 6360 6391 6361 6392 /* Line 1806 of yacc.c */ 6362 #line 114 1"parser.yy"6393 #line 1147 "parser.yy" 6363 6394 { 6364 6395 typedefTable.addToEnclosingScope( TypedefTable::ID ); … … 6370 6401 6371 6402 /* Line 1806 of yacc.c */ 6372 #line 11 46"parser.yy"6403 #line 1152 "parser.yy" 6373 6404 { 6374 6405 typedefTable.addToEnclosingScope( *(yyvsp[(5) - (5)].tok), TypedefTable::ID ); … … 6380 6411 6381 6412 /* Line 1806 of yacc.c */ 6382 #line 11 77"parser.yy"6413 #line 1183 "parser.yy" 6383 6414 { 6384 6415 (yyval.decl) = DeclarationNode::newFunction( (yyvsp[(2) - (7)].tok), (yyvsp[(1) - (7)].decl), (yyvsp[(5) - (7)].decl), 0, true ); … … 6389 6420 6390 6421 /* Line 1806 of yacc.c */ 6391 #line 118 1"parser.yy"6422 #line 1187 "parser.yy" 6392 6423 { 6393 6424 (yyval.decl) = DeclarationNode::newFunction( (yyvsp[(2) - (7)].tok), (yyvsp[(1) - (7)].decl), (yyvsp[(5) - (7)].decl), 0, true ); … … 6398 6429 6399 6430 /* Line 1806 of yacc.c */ 6400 #line 11 88"parser.yy"6431 #line 1194 "parser.yy" 6401 6432 { (yyval.decl) = DeclarationNode::newTuple( (yyvsp[(3) - (5)].decl) ); } 6402 6433 break; … … 6405 6436 6406 6437 /* Line 1806 of yacc.c */ 6407 #line 119 2"parser.yy"6438 #line 1198 "parser.yy" 6408 6439 { (yyval.decl) = DeclarationNode::newTuple( (yyvsp[(3) - (9)].decl)->appendList( (yyvsp[(7) - (9)].decl) ) ); } 6409 6440 break; … … 6412 6443 6413 6444 /* Line 1806 of yacc.c */ 6414 #line 1 197"parser.yy"6445 #line 1203 "parser.yy" 6415 6446 { 6416 6447 typedefTable.addToEnclosingScope( TypedefTable::TD ); … … 6422 6453 6423 6454 /* Line 1806 of yacc.c */ 6424 #line 120 2"parser.yy"6455 #line 1208 "parser.yy" 6425 6456 { 6426 6457 typedefTable.addToEnclosingScope( TypedefTable::TD ); … … 6432 6463 6433 6464 /* Line 1806 of yacc.c */ 6434 #line 12 07"parser.yy"6465 #line 1213 "parser.yy" 6435 6466 { 6436 6467 typedefTable.addToEnclosingScope( *(yyvsp[(5) - (5)].tok), TypedefTable::TD ); … … 6442 6473 6443 6474 /* Line 1806 of yacc.c */ 6444 #line 12 18"parser.yy"6475 #line 1224 "parser.yy" 6445 6476 { 6446 6477 typedefTable.addToEnclosingScope( TypedefTable::TD ); … … 6452 6483 6453 6484 /* Line 1806 of yacc.c */ 6454 #line 122 3"parser.yy"6485 #line 1229 "parser.yy" 6455 6486 { 6456 6487 typedefTable.addToEnclosingScope( TypedefTable::TD ); … … 6462 6493 6463 6494 /* Line 1806 of yacc.c */ 6464 #line 12 28"parser.yy"6495 #line 1234 "parser.yy" 6465 6496 { 6466 6497 typedefTable.addToEnclosingScope( TypedefTable::TD ); … … 6472 6503 6473 6504 /* Line 1806 of yacc.c */ 6474 #line 123 3"parser.yy"6505 #line 1239 "parser.yy" 6475 6506 { 6476 6507 typedefTable.addToEnclosingScope( TypedefTable::TD ); … …