Changes in / [67fa9f9:11dbfe1]
- Files:
-
- 1 added
- 7 deleted
- 65 edited
-
.gitignore (modified) (1 diff)
-
doc/LaTeXmacros/lstlang.sty (modified) (2 diffs)
-
doc/generic_types/mail (modified) (1 diff)
-
doc/proposals/references.md (modified) (3 diffs)
-
doc/user/EHMHierarchy.fig (deleted)
-
doc/user/Makefile (modified) (1 diff)
-
doc/user/user.tex (modified) (20 diffs)
-
src/CodeGen/CodeGenerator.cc (modified) (3 diffs)
-
src/CodeGen/CodeGenerator.h (modified) (2 diffs)
-
src/Common/PassVisitor.h (modified) (9 diffs)
-
src/Common/PassVisitor.impl.h (modified) (9 diffs)
-
src/Common/PassVisitor.proto.h (modified) (3 diffs)
-
src/Common/utility.h (modified) (1 diff)
-
src/ControlStruct/ExceptTranslate.cc (modified) (27 diffs)
-
src/ControlStruct/ExceptTranslate.h (modified) (2 diffs)
-
src/ControlStruct/module.mk (modified) (1 diff)
-
src/GenPoly/Box.cc (modified) (4 diffs)
-
src/GenPoly/InstantiateGeneric.cc (modified) (10 diffs)
-
src/InitTweak/FixInit.cc (modified) (8 diffs)
-
src/InitTweak/GenInit.cc (modified) (8 diffs)
-
src/InitTweak/InitTweak.cc (modified) (1 diff)
-
src/MakeLibCfa.cc (modified) (1 diff)
-
src/Makefile.in (modified) (12 diffs)
-
src/Parser/InitializerNode.cc (modified) (1 diff)
-
src/Parser/TypeData.cc (modified) (2 diffs)
-
src/Parser/parser.yy (modified) (4 diffs)
-
src/ResolvExpr/AlternativeFinder.cc (modified) (4 diffs)
-
src/ResolvExpr/AlternativeFinder.h (modified) (1 diff)
-
src/ResolvExpr/CurrentObject.cc (deleted)
-
src/ResolvExpr/CurrentObject.h (deleted)
-
src/ResolvExpr/Resolver.cc (modified) (10 diffs)
-
src/ResolvExpr/Unify.cc (modified) (4 diffs)
-
src/ResolvExpr/module.mk (modified) (2 diffs)
-
src/SymTab/Autogen.h (modified) (3 diffs)
-
src/SymTab/ImplementationType.cc (modified) (2 diffs)
-
src/SymTab/Indexer.cc (modified) (4 diffs)
-
src/SymTab/Validate.cc (modified) (9 diffs)
-
src/SynTree/Constant.cc (modified) (2 diffs)
-
src/SynTree/Constant.h (modified) (2 diffs)
-
src/SynTree/Expression.cc (modified) (3 diffs)
-
src/SynTree/Expression.h (modified) (1 diff)
-
src/SynTree/Initializer.cc (modified) (3 diffs)
-
src/SynTree/Initializer.h (modified) (7 diffs)
-
src/SynTree/Mutator.cc (modified) (4 diffs)
-
src/SynTree/Mutator.h (modified) (2 diffs)
-
src/SynTree/SynTree.h (modified) (2 diffs)
-
src/SynTree/TupleType.cc (modified) (1 diff)
-
src/SynTree/Type.h (modified) (3 diffs)
-
src/SynTree/VarExprReplacer.cc (modified) (1 diff)
-
src/SynTree/VarExprReplacer.h (modified) (1 diff)
-
src/SynTree/Visitor.cc (modified) (4 diffs)
-
src/SynTree/Visitor.h (modified) (2 diffs)
-
src/Tuples/TupleExpansion.cc (modified) (2 diffs)
-
src/libcfa/Makefile.am (modified) (1 diff)
-
src/libcfa/Makefile.in (modified) (9 diffs)
-
src/libcfa/exception.c (modified) (8 diffs)
-
src/libcfa/exception.h (modified) (1 diff)
-
src/libcfa/fstream (modified) (3 diffs)
-
src/libcfa/fstream.c (modified) (6 diffs)
-
src/libcfa/iostream (modified) (4 diffs)
-
src/libcfa/iostream.c (modified) (3 diffs)
-
src/libcfa/lsda.h (deleted)
-
src/main.cc (modified) (4 diffs)
-
src/prelude/Makefile.am (modified) (2 diffs)
-
src/prelude/Makefile.in (modified) (2 diffs)
-
src/tests/.expect/designations.txt (deleted)
-
src/tests/.expect/io.txt (modified) (3 diffs)
-
src/tests/designations.c (deleted)
-
src/tests/except-0.c (deleted)
-
src/tests/exception.c (added)
-
src/tests/io.c (modified) (9 diffs)
-
tools/cfa.nanorc (modified) (3 diffs)
-
tools/prettyprinter/main.cc (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
.gitignore
r67fa9f9 r11dbfe1 54 54 doc/user/pointer1.tex 55 55 doc/user/pointer2.tex 56 doc/user/EHMHierarchy.tex -
doc/LaTeXmacros/lstlang.sty
r67fa9f9 r11dbfe1 8 8 %% Created On : Sat May 13 16:34:42 2017 9 9 %% Last Modified By : Peter A. Buhr 10 %% Last Modified On : Thu Jun 22 07:40:31201711 %% Update Count : 1010 %% Last Modified On : Fri May 26 12:47:09 2017 11 %% Update Count : 8 12 12 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13 13 … … 116 116 _Atomic, coroutine, is_coroutine, is_monitor, is_thread, monitor, mutex, nomutex, 117 117 resume, suspend, thread, _Thread_local, yield}, 118 moredirectives={defined,include_next}%119 118 } 120 119 -
doc/generic_types/mail
r67fa9f9 r11dbfe1 78 78 79 79 - OOPSLA'17 Submissions 80 81 82 83 From: "OOPSLA'17 HotCRP" <noreply@oopsla17.hotcrp.com>84 Subject: [OOPSLA'17] Paper #20 "Generic and Tuple Types with Efficient..."85 To: Peter Buhr <pabuhr@uwaterloo.ca>86 Cc: jonathan.aldrich@cs.cmu.edu87 Reply-To: jonathan.aldrich@cs.cmu.edu88 Date: Wed, 7 Jun 2017 13:33:40 +0000 (UTC)89 90 Dear Peter Buhr,91 92 The author response period for OOPSLA has started, and will continue until93 the end of June 10th (Anywhere on Earth). No email with a snapshot of your94 reviews will be sent: you can see the live version of reviews (including95 current updates) on the HotCRP system (links at the bottom).96 97 An author response should aim to:98 -correct reviewers' mistakes or misunderstandings99 -offer new information only when this addresses reviewers' concerns (e.g.,100 "I wonder if A might work better..."; "we tried that, but...")101 -answer explicit questions by the reviewers. The key questions will be in a102 designated "Questions for Author Response" entry of a review.103 104 Please keep in mind that an author response is *not* a "rebuttal". You are105 not rebutting an opponent's arguments with your own, in front of an106 audience that weighs both sets of arguments. Instead, your audience is the107 same reviewers who offered the comments in the first place, and their108 subjective weighing of different factors is very unlikely to change.109 110 During author response, please keep in mind that the reviewers are still111 unaware of author identity. If you need to refer to author-identifying112 information during your response, the ideal course of action is to place it113 at an external location and include a URL, with an explicit warning (e.g.,114 "WARNING: following this link will reveal author identity").115 116 As with all external resources, your response should be self-contained,117 without consulting them. That is, the author-visible external URL is just118 evidence, but the claim that this evidence supports should be clear in the119 response text. For instance:120 "we have received public feedback from the developers of X that confirm the121 issue [supporting URL] (WARNING: following this link will reveal author122 identity)"123 124 Your paper's access information is below:125 126 Title: Generic and Tuple Types with Efficient Dynamic Layout in C∀127 Paper site: https://oopsla17.hotcrp.com/paper/20128 129 Use the link below to sign in to the site.130 131 https://oopsla17.hotcrp.com/?email=pabuhr%40uwaterloo.ca132 133 Please contact me <jonathan.aldrich@cs.cmu.edu> with any questions or134 concerns.135 136 Best Regards and wishes for a constructive response,137 138 Jonathan Aldrich139 140 141 142 From: "OOPSLA'17 HotCRP" <noreply@oopsla17.hotcrp.com>143 Subject: [OOPSLA'17] Paper #20 "Generic and Tuple Types with Efficient..."144 To: Peter Buhr <pabuhr@uwaterloo.ca>145 Cc: jonathan.aldrich@cs.cmu.edu146 Reply-To: jonathan.aldrich@cs.cmu.edu147 Date: Tue, 20 Jun 2017 00:33:10 +0000 (UTC)148 149 Dear Peter Buhr,150 151 I regret to inform you that your submission to OOPSLA'17 listed below has not152 been selected for the second phase of the review process. I understand this is153 not welcome news but selection was very competitive: 157 of the 223 papers154 submitted did not advance to the second phase. For several of these, there was155 a clear impression that in the future they can evolve into some of the156 strongest results of our community.157 158 Title: Generic and Tuple Types with Efficient Dynamic Layout in C∀159 Paper site: https://oopsla17.hotcrp.com/paper/20160 Login link: https://oopsla17.hotcrp.com/?email=pabuhr%40uwaterloo.ca161 162 Below you will find reviews, as well as author-visible comments--the latter may163 include further communication. I hope you will find the reviewers' feedback164 useful.165 166 Best Regards,167 168 - Jonathan Aldrich <jonathan.aldrich@cs.cmu.edu>, for OOPSLA 2017169 Submissions170 171 172 173 ===========================================================================174 OOPSLA'17 Review #20A175 ---------------------------------------------------------------------------176 Paper #20: Generic and Tuple Types with Efficient Dynamic Layout in C∀177 ---------------------------------------------------------------------------178 179 Overall merit: C. Weak paper, though I will not fight180 strongly against it181 Confidence: X. I am an expert in this area182 183 ===== Paper summary =====184 185 This presents an extension of the C programming language that tries to preserve the character of the existing language, while adding tuples and generics. Unlike C++ templates, generics preserve separate compilation. Types are represented at runtime, if needed, by size and alignment values, along with pointers to the code for any needed operators. A microbenchmark performance comparison is provided.186 187 ===== Comments for author =====188 189 This is an interesting extension to C, that may be of interest to some C programmers. It generally seems to be fairly well engineered, and mostly respects C's design goals.190 191 Unfortunately, there have been enough proposals for extended C dialects that this sort of design is tough to sell. And I don't think the evaluation really went far enough to make that case.192 193 The ideas in the paper don't appear to be fundamentally new. The idea of passing types as runtime objects has certainly been explored before. An additional ancient reference is http://dl.acm.org/citation.cfm?doid=13310.13330.194 195 There seems to be a new idea of minimally describing types using alignment and size attributes instead of (?) pointers to assignment operators and the like. But this scheme is not very well described. Notably, it is not clear how, say, a struct with atomic field or bit-fields would be described.196 197 I wasn't quite clear on the extent to which operator overloading is supported. The MAX example appears to me like it would be quite controversial among C programmers.198 199 It is not obvious that type inference here always converges. An outline of the algorithm would be useful.200 201 Above all, this needs experience results from a more complete implementation.202 203 Details:204 205 Relying on TIOBE here seems a bit dubious. Since it counts web pages, and C isn't exactly new and hot, it may actually understate your case.206 207 The print example seems a little simplistic, since it's not clear how it handles formatting.208 209 "does not using the return type"210 211 ===== Questions for authors’ response =====212 213 How are atomics, volatile, and bit-fields in structs handled?214 215 ===========================================================================216 OOPSLA'17 Review #20B217 ---------------------------------------------------------------------------218 Paper #20: Generic and Tuple Types with Efficient Dynamic Layout in C∀219 ---------------------------------------------------------------------------220 221 Overall merit: D. Reject222 Confidence: X. I am an expert in this area223 224 ===== Paper summary =====225 226 The authors present an extension to C, adding universal polymorphism and tuples. These features are described in prose. There is an implementation, though this is not described in depth in the paper. There is a benchmark evaluation.227 228 ===== Comments for author =====229 230 The paper is well-written and the concepts explained well. It is nice to see work in the low-level/C space - I believe that it is an area that has not been well-served by the OOPSLA community. My concerns with the paper are that the contribution is rather small and the concepts are not well-evaluated; specifically this is a language design paper and there is no attempt to evaluate the actual language design.231 232 While it is reasonable to describe only a couple of features in a paper, I would then expect a detailed description of the implementation and/or a formalism with proven safety properties and a thorough evaluation of the design. For a paper which only describes the design of a language the bar is higher than two features - for example, a description of a 'large' language such as D or Rust, even then I would expect a stronger evaluation.233 234 ## On the design of C-forall235 236 There are some interesting points in the design of generics, notably the otype/dtype distinction. The design seems reasonable and follows what I would expect from other languages. The design for tuples is more unusual - the usual design of simple anonymous records with anonymous fields is extended with a mix of 'spread'ing, variadics, and implicit conversions. Importantly, the authors neither justify nor evaluate this departure - that is a severe omission for this paper. Furthermore, the only in-depth description of the implementation in the paper concerns tuples, and it seems to me that this is only interesting because of the unusual design - further reason for justifying it.237 238 ## Evaluation239 240 The paper evaluates the implementation of C-forall with (effectively) a single micro-benchmark. That benchmark seems to show that C-forall performs worse than C++ on every measure, but this is not really discussed.241 242 A better performance evaluation would consist of multiple tests, both micro-benchmarks and realistic code and would test C-forall compared to alternatives (D, Rust, Go, etc.) not just C/C++.243 244 However, performance is not the really interesting thing to test here. The authors propose a new language and while performance is an important consideration for systems languages, it is far from the most important. I would like to see the usability of the language tested with user studies of different kinds (various levels of skill-level and coding scenarios). The authors could also use case studies or programming idioms to compare programming in C-forall vs the alternatives (again, comparing with D, Rust, etc. is more interesting to me than C).245 246 Finally, in designing C-forall, the authors make several assumptions about why C programmers use C. These should be backed up either with evaluation or citation. Statements in the paper certainly do not reflect my experience discussing language design with C programmers, and I would like to see them verified.247 248 249 ## Related work250 251 The related work section is broad and gives good descriptions of other languages. However, the comparisons between languages focus more on the high-level goals of the language. It would be more interesting to focus on the details of the languages - the comparisons between Cyclone, C++, Java, and C-forall generics are good, I would like to see more of this with D and Rust, which are the more modern alternatives to C-forall (for example, Rust's notion of Sized and ?Sized types seems similar to otypes/dtypes).252 253 The related work is really missing any discussion of why the C-forall design choices are better than other languages. To clarify, I mean the specific design of generics and tuples, c.f., the suitability of the language in general because of garbage collection or learning difficulties.254 255 ===========================================================================256 OOPSLA'17 Review #20C257 ---------------------------------------------------------------------------258 Paper #20: Generic and Tuple Types with Efficient Dynamic Layout in C∀259 ---------------------------------------------------------------------------260 261 Overall merit: D. Reject262 Confidence: Z. I am not an expert; my evaluation263 is that of an informed outsider264 265 ===== Paper summary =====266 267 The paper presents two language features of "Cforall": generics and tuples.268 269 ===== Comments for author =====270 271 The authors really need to talk about C++ as early as possible IMHO. That's the first thing that came to mind when reading the abstract: how is this different from C++?272 273 Comparison with C++:274 The main difference with C++ seems to be that Cforall favors separate compilation at the expense of runtime overhead while C++ systematically avoids any runtime overhead (at the expense of slow compilation times). C++ approach makes more sense IMHO. While it's true that people where using C for almost everything 30 years ago, that is just not true anymore. Most people writing C today are doing system programming, otherwise there would be using a higher level programming language (C#, Java etc ...).275 Now, when doing system programming, one needs very fine grain control over the resources: memory layout, etc ...276 It is pretty clear to me that the people writing that kind of code will favor generics that do not cost any overhead at runtime, otherwise they would be writing Java in the first place.277 The authors need to better justify the runtime overhead, or give escape hatches for those who don't want to pay that cost at runtime.278 They very often go back to the benefit of separate compilation, but that's not enough IMHO. Here is a proposal: why not have 2 modes, one called debug mode, used while developing the code, that would compile generics with a runtime overhead. Another, called production, that would unfold the world like C++ does?279 280 About Tuples:281 The section about tuples is too long. I would have spent more time explaining generics.282 283 Feedback:284 "This installation base"285 Unclear what you mean by that.286 287 "Prior projects ... but failed ..."288 Hummm ... What about C++.289 290 "... object-oriented or functional programming with garbage collection ..."291 You are really mixing apples and oranges here. Many C programmers have nothing agains object-oriented features, not even functional programming (C++ 11 adds292 a bunch of features proving my point), but it's clear that most of them feel very strongly against automated garbage collection.293 294 "In many cases, C++ is often ..."295 This sentence feels like it is coming out of nowhere.296 297 "... the polymorphic runtime-cost ..."298 Is there any way to avoid that overhead? It's true it will make the compiler faster, but there are cases where the user might not want to pay for299 the overhead at runtime. Is there a way to force the compiler to specialize the code?300 301 "... to write a type-safe Cforall wrapper malloc based ..."302 That cannot be true in general. Malloc produces a pointer (of any type), given an integer (the size).303 It looks like Cforall is assuming that the integer is the result of a call to sizeof (a good practice in C).304 However, if that's the case, it should be explained.305 306 "... allows variable overloading ..."307 How are conflict resolved? In other words, what happens when two variables could be used?308 309 "... reuses the generated structure declarations where appropriate."310 This is too vague.311 312 "... have multiple outcomes, some exceptional."313 Humm, I would say these two things are distinct. Let's just way that this way of presenting things is strange, I woulds ay that a function can either314 return one or multiple values or throw an exception. Not that some of the values returned are "exceptional".315 316 "The type-resolver ..."317 What's that? Type-checker? Type-inference?318 319 "... applies C conversions."320 Noooo! That's exactly what leads to very subtle bugs. Is there any way to stop those conversions from happening?321 322 "The minimal cost ..."323 In what regard? Runtime cost? How does the "resolver" know how expensive the conversions are?324 325 "z = 10 // mass assignments"326 That stuff is completely unreadable. Why not introduce a new operator?327 328 "... roughly equivalent time ..."329 Well, C++ looks faster to me.330 331 "... is restricted because the resolution does not using ..."332 Did you mean, does not use?333 334 "... D and go are garbage collected ..."335 Yes, but in D, the use of the GC is optional.336 337 "... while respecting the talent and skill of C programmers."338 Are you implying that other approaches are not?339 340 "On the surface, the project may appear as a rehash of similar mechanisms in C++."341 Absolutely.342 343 "... integration with C and its programmers ..."344 Bold claim. What makes you think you are integrated with programmers? Number of users?345 346 "... inline annotation at polymorphic function call sites to create a template-specialization ..."347 This should have been mentioned sooner. Plus conflating inlining and specialization is unfortunate.348 Does "inline" also inline the function? Or does it only specialize the code?349 If it also inline, that's a very unfortunate design. I might want to specialize the code, but without inlining ...350 How do I specialize a recursive function? -
doc/proposals/references.md
r67fa9f9 r11dbfe1 17 17 derived rvalue types such as pointer types may include qualifiers; 18 18 `const int *` is a distinct type from `int *`, though the latter is safely 19 convert ible to the former.19 convertable to the former. 20 20 In general, any number of qualifiers can be safely added to the 21 21 pointed-to-type of a pointer type, e.g. `int *` converts safely to … … 23 23 `const volatile int *`. 24 24 25 Since lvalues are preci sely "addressable objects", in C, only lvalues can be25 Since lvalues are precicely "addressable objects", in C, only lvalues can be 26 26 used as the operand of the `&` address-of operator. 27 27 Similarly, only modifiable lvalues may be used as the assigned-to … … 147 147 call "lvalue of type `T`" as `T&`. 148 148 There's also an obvious argument that lvalues of a (possibly-qualified) type 149 `T` should be convert ible to references of type `T`, where `T` is also149 `T` should be convertable to references of type `T`, where `T` is also 150 150 so-qualified (e.g. lvalue `int` to `int&`, lvalue `const char` to 151 151 `const char&`). 152 152 By similar arguments to pointer types, qualifiers should be addable to the 153 153 referred-to type of a reference (e.g. `int&` to `const int&`). 154 As a note, since pointer arithmetic is explic itly not defined on `T&`,154 As a note, since pointer arithmetic is explictly not defined on `T&`, 155 155 `restrict T&` should be allowable and would have alias-analysis rules that 156 156 are actually comprehensible to mere mortals. -
doc/user/Makefile
r67fa9f9 r11dbfe1 12 12 13 13 FIGURES = ${addsuffix .tex, \ 14 EHMHierarchy \15 14 Cdecl \ 16 15 pointer1 \ -
doc/user/user.tex
r67fa9f9 r11dbfe1 11 11 %% Created On : Wed Apr 6 14:53:29 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Sun Jul 2 09:49:56201714 %% Update Count : 2 50313 %% Last Modified On : Fri Jun 16 12:00:01 2017 14 %% Update Count : 2433 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 25 25 \usepackage{textcomp} 26 26 \usepackage[latin1]{inputenc} 27 % Default underscore is too low and wide. Cannot use lstlisting "literate" as replacing underscore 28 % removes it as a variable-name character so keyworks in variables are highlighted 29 \DeclareTextCommandDefault{\textunderscore}{\leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.1ex}}} 30 27 31 28 32 \usepackage{fullpage,times,comment} … … 44 48 \renewcommand{\UrlFont}{\small\sf} 45 49 46 % Default underscore is too low and wide. Cannot use lstlisting "literate" as replacing underscore47 % removes it as a variable-name character so keywords in variables are highlighted. MUST APPEAR48 % AFTER HYPERREF.49 \renewcommand{\_}{\leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.075ex}}}50 \renewcommand{\textunderscore}{\leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.075ex}}}51 52 50 \setlength{\topmargin}{-0.45in} % move running title into header 53 51 \setlength{\headsep}{0.25in} … … 112 110 \renewcommand{\subsectionmark}[1]{\markboth{\thesubsection\quad #1}{\thesubsection\quad #1}} 113 111 \pagenumbering{roman} 114 \linenumbers % comment out to turn off line numbering112 %\linenumbers % comment out to turn off line numbering 115 113 116 114 \maketitle … … 479 477 #endif // ! otype 480 478 481 # ®include_next®<bfd.h> §\C{// must have internal check for multiple expansion}§479 #include_next <bfd.h> §\C{// must have internal check for multiple expansion}§ 482 480 483 481 #if defined( otype ) && defined( __CFA_BFD_H__ ) §\C{// reset only if set}§ … … 489 487 \label{f:InterpositionHeaderFile} 490 488 \end{figure} 489 490 491 \section{Declarations} 492 \label{s:Declarations} 493 494 C declaration syntax is notoriously confusing and error prone. 495 For example, many C programmers are confused by a declaration as simple as: 496 \begin{quote2} 497 \begin{tabular}{@{}ll@{}} 498 \begin{cfa} 499 int * x[5] 500 \end{cfa} 501 & 502 \raisebox{-0.75\totalheight}{\input{Cdecl}} 503 \end{tabular} 504 \end{quote2} 505 Is this an array of 5 pointers to integers or a \Index{pointer} to an array of 5 integers? 506 The fact this declaration is unclear to many C programmers means there are \Index{productivity} and \Index{safety} issues even for basic programs. 507 Another example of confusion results from the fact that a routine name and its parameters are embedded within the return type, mimicking the way the return value is used at the routine's call site. 508 For example, a routine returning a \Index{pointer} to an array of integers is defined and used in the following way: 509 \begin{cfa} 510 int ®(*®f®())[®5®]® {...}; §\C{definition}§ 511 ... ®(*®f®())[®3®]® += 1; §\C{usage}§ 512 \end{cfa} 513 Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}). 514 While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice. 515 516 \CFA provides its own type, variable and routine declarations, using a different syntax. 517 The new declarations place qualifiers to the left of the base type, while C declarations place qualifiers to the right of the base type. 518 In the following example, \R{red} is the base type and \B{blue} is qualifiers. 519 The \CFA declarations move the qualifiers to the left of the base type, \ie move the blue to the left of the red, while the qualifiers have the same meaning but are ordered left to right to specify a variable's type. 520 \begin{quote2} 521 \begin{tabular}{@{}l@{\hspace{3em}}l@{}} 522 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 523 \begin{cfa} 524 ß[5] *ß ®int® x1; 525 ß* [5]ß ®int® x2; 526 ß[* [5] int]ß f®( int p )®; 527 \end{cfa} 528 & 529 \begin{cfa} 530 ®int® ß*ß x1 ß[5]ß; 531 ®int® ß(*ßx2ß)[5]ß; 532 ßint (*ßf®( int p )®ß)[5]ß; 533 \end{cfa} 534 \end{tabular} 535 \end{quote2} 536 The only exception is \Index{bit field} specification, which always appear to the right of the base type. 537 % Specifically, the character ©*© is used to indicate a pointer, square brackets ©[©\,©]© are used to represent an array or function return value, and parentheses ©()© are used to indicate a routine parameter. 538 However, unlike C, \CFA type declaration tokens are distributed across all variables in the declaration list. 539 For instance, variables ©x© and ©y© of type \Index{pointer} to integer are defined in \CFA as follows: 540 \begin{quote2} 541 \begin{tabular}{@{}l@{\hspace{3em}}l@{}} 542 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 543 \begin{cfa} 544 ®*® int x, y; 545 \end{cfa} 546 & 547 \begin{cfa} 548 int ®*®x, ®*®y; 549 \end{cfa} 550 \end{tabular} 551 \end{quote2} 552 The downside of this semantics is the need to separate regular and \Index{pointer} declarations: 553 \begin{quote2} 554 \begin{tabular}{@{}l@{\hspace{3em}}l@{}} 555 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 556 \begin{cfa} 557 ®*® int x; 558 int y; 559 \end{cfa} 560 & 561 \begin{cfa} 562 int ®*®x, y; 563 564 \end{cfa} 565 \end{tabular} 566 \end{quote2} 567 which is \Index{prescribing} a safety benefit. 568 Other examples are: 569 \begin{quote2} 570 \begin{tabular}{@{}l@{\hspace{3em}}l@{\hspace{2em}}l@{}} 571 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c@{\hspace{2em}}}{\textbf{C}} \\ 572 \begin{cfa} 573 [ 5 ] int z; 574 [ 5 ] * char w; 575 * [ 5 ] double v; 576 struct s { 577 int f0:3; 578 * int f1; 579 [ 5 ] * int f2; 580 }; 581 \end{cfa} 582 & 583 \begin{cfa} 584 int z[ 5 ]; 585 char * w[ 5 ]; 586 double (* v)[ 5 ]; 587 struct s { 588 int f0:3; 589 int * f1; 590 int * f2[ 5 ] 591 }; 592 \end{cfa} 593 & 594 \begin{cfa} 595 // array of 5 integers 596 // array of 5 pointers to char 597 // pointer to array of 5 doubles 598 599 // common bit field syntax 600 601 602 603 \end{cfa} 604 \end{tabular} 605 \end{quote2} 606 607 All type qualifiers, \eg ©const©, ©volatile©, etc., are used in the normal way with the new declarations and also appear left to right, \eg: 608 \begin{quote2} 609 \begin{tabular}{@{}l@{\hspace{1em}}l@{\hspace{1em}}l@{}} 610 \multicolumn{1}{c@{\hspace{1em}}}{\textbf{\CFA}} & \multicolumn{1}{c@{\hspace{1em}}}{\textbf{C}} \\ 611 \begin{cfa} 612 const * const int x; 613 const * [ 5 ] const int y; 614 \end{cfa} 615 & 616 \begin{cfa} 617 int const * const x; 618 const int (* const y)[ 5 ] 619 \end{cfa} 620 & 621 \begin{cfa} 622 // const pointer to const integer 623 // const pointer to array of 5 const integers 624 \end{cfa} 625 \end{tabular} 626 \end{quote2} 627 All declaration qualifiers, \eg ©extern©, ©static©, etc., are used in the normal way with the new declarations but can only appear at the start of a \CFA routine declaration,\footnote{\label{StorageClassSpecifier} 628 The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature.~\cite[\S~6.11.5(1)]{C11}} \eg: 629 \begin{quote2} 630 \begin{tabular}{@{}l@{\hspace{3em}}l@{\hspace{2em}}l@{}} 631 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c@{\hspace{2em}}}{\textbf{C}} \\ 632 \begin{cfa} 633 extern [ 5 ] int x; 634 static * const int y; 635 \end{cfa} 636 & 637 \begin{cfa} 638 int extern x[ 5 ]; 639 const int static * y; 640 \end{cfa} 641 & 642 \begin{cfa} 643 // externally visible array of 5 integers 644 // internally visible pointer to constant int 645 \end{cfa} 646 \end{tabular} 647 \end{quote2} 648 649 The new declaration syntax can be used in other contexts where types are required, \eg casts and the pseudo-routine ©sizeof©: 650 \begin{quote2} 651 \begin{tabular}{@{}l@{\hspace{3em}}l@{}} 652 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 653 \begin{cfa} 654 y = (®* int®)x; 655 i = sizeof(®[ 5 ] * int®); 656 \end{cfa} 657 & 658 \begin{cfa} 659 y = (®int *®)x; 660 i = sizeof(®int * [ 5 ]®); 661 \end{cfa} 662 \end{tabular} 663 \end{quote2} 664 665 Finally, new \CFA declarations may appear together with C declarations in the same program block, but cannot be mixed within a specific declaration. 666 Therefore, a programmer has the option of either continuing to use traditional C declarations or take advantage of the new style. 667 Clearly, both styles need to be supported for some time due to existing C-style header-files, particularly for UNIX systems. 668 669 670 \section{Pointer/Reference} 671 672 C provides a \newterm{pointer type}; 673 \CFA adds a \newterm{reference type}. 674 These types may be derived from an object or routine type, called the \newterm{referenced type}. 675 Objects of these types contain an \newterm{address}, which is normally a location in memory, but may also address memory-mapped registers in hardware devices. 676 An integer constant expression with the value 0, or such an expression cast to type ©void *©, is called a \newterm{null-pointer constant}.\footnote{ 677 One way to conceptualize the null pointer is that no variable is placed at this address, so the null-pointer address can be used to denote an uninitialized pointer/reference object; 678 \ie the null pointer is guaranteed to compare unequal to a pointer to any object or routine.} 679 An address is \newterm{sound}, if it points to a valid memory location in scope, \ie within the program's execution-environment and has not been freed. 680 Dereferencing an \newterm{unsound} address, including the null pointer, is \Index{undefined}, often resulting in a \Index{memory fault}. 681 682 A program \newterm{object} is a region of data storage in the execution environment, the contents of which can represent values. 683 In most cases, objects are located in memory at an address, and the variable name for an object is an implicit address to the object generated by the compiler and automatically dereferenced, as in: 684 \begin{quote2} 685 \begin{tabular}{@{}ll@{\hspace{2em}}l@{}} 686 \begin{cfa} 687 int x; 688 x = 3; 689 int y; 690 y = x; 691 \end{cfa} 692 & 693 \raisebox{-0.45\totalheight}{\input{pointer1}} 694 & 695 \begin{cfa} 696 int * ®const® x = (int *)100 697 *x = 3; // implicit dereference 698 int * ®const® y = (int *)104; 699 *y = *x; // implicit dereference 700 \end{cfa} 701 \end{tabular} 702 \end{quote2} 703 where the right example is how the compiler logically interprets the variables in the left example. 704 Since a variable name only points to one address during its lifetime, it is an \Index{immutable} \Index{pointer}; 705 hence, the implicit type of pointer variables ©x© and ©y© are constant pointers in the compiler interpretation. 706 In general, variable addresses are stored in instructions instead of loaded from memory, and hence may not occupy storage. 707 These approaches are contrasted in the following: 708 \begin{quote2} 709 \begin{tabular}{@{}l|l@{}} 710 \multicolumn{1}{c|}{explicit variable address} & \multicolumn{1}{c}{implicit variable address} \\ 711 \hline 712 \begin{cfa} 713 lda r1,100 // load address of x 714 ld r2,(r1) // load value of x 715 lda r3,104 // load address of y 716 st r2,(r3) // store x into y 717 \end{cfa} 718 & 719 \begin{cfa} 720 721 ld r2,(100) // load value of x 722 723 st r2,(104) // store x into y 724 \end{cfa} 725 \end{tabular} 726 \end{quote2} 727 Finally, the immutable nature of a variable's address and the fact that there is no storage for the variable pointer means pointer assignment\index{pointer!assignment}\index{assignment!pointer} is impossible. 728 Therefore, the expression ©x = y© has only one meaning, ©*x = *y©, \ie manipulate values, which is why explicitly writing the dereferences is unnecessary even though it occurs implicitly as part of \Index{instruction decoding}. 729 730 A \Index{pointer}/\Index{reference} object is a generalization of an object variable-name, \ie a mutable address that can point to more than one memory location during its lifetime. 731 (Similarly, an integer variable can contain multiple integer literals during its lifetime versus an integer constant representing a single literal during its lifetime, and like a variable name, may not occupy storage if the literal is embedded directly into instructions.) 732 Hence, a pointer occupies memory to store its current address, and the pointer's value is loaded by dereferencing, \eg: 733 \begin{quote2} 734 \begin{tabular}{@{}l@{\hspace{2em}}l@{}} 735 \begin{cfa} 736 int x, y, ®*® p1, ®*® p2, ®**® p3; 737 p1 = ®&®x; // p1 points to x 738 p2 = p1; // p2 points to x 739 p1 = ®&®y; // p1 points to y 740 p3 = &p2; // p3 points to p2 741 \end{cfa} 742 & 743 \raisebox{-0.5\totalheight}{\input{pointer2.pstex_t}} 744 \end{tabular} 745 \end{quote2} 746 747 Notice, an address has a \Index{duality}\index{address!duality}: a location in memory or the value at that location. 748 In many cases, a compiler might be able to infer the best meaning for these two cases. 749 For example, \Index*{Algol68}~\cite{Algol68} infers pointer dereferencing to select the best meaning for each pointer usage 750 \begin{cfa} 751 p2 = p1 + x; §\C{// compiler infers *p2 = *p1 + x;}§ 752 \end{cfa} 753 Algol68 infers the following dereferencing ©*p2 = *p1 + x©, because adding the arbitrary integer value in ©x© to the address of ©p1© and storing the resulting address into ©p2© is an unlikely operation. 754 Unfortunately, automatic dereferencing does not work in all cases, and so some mechanism is necessary to fix incorrect choices. 755 756 Rather than inferring dereference, most programming languages pick one implicit dereferencing semantics, and the programmer explicitly indicates the other to resolve address-duality. 757 In C, objects of pointer type always manipulate the pointer object's address: 758 \begin{cfa} 759 p1 = p2; §\C{// p1 = p2\ \ rather than\ \ *p1 = *p2}§ 760 p2 = p1 + x; §\C{// p2 = p1 + x\ \ rather than\ \ *p2 = *p1 + x}§ 761 \end{cfa} 762 even though the assignment to ©p2© is likely incorrect, and the programmer probably meant: 763 \begin{cfa} 764 p1 = p2; §\C{// pointer address assignment}§ 765 ®*®p2 = ®*®p1 + x; §\C{// pointed-to value assignment / operation}§ 766 \end{cfa} 767 The C semantics work well for situations where manipulation of addresses is the primary meaning and data is rarely accessed, such as storage management (©malloc©/©free©). 768 769 However, in most other situations, the pointed-to value is requested more often than the pointer address. 770 \begin{cfa} 771 *p2 = ((*p1 + *p2) * (**p3 - *p1)) / (**p3 - 15); 772 \end{cfa} 773 In this case, it is tedious to explicitly write the dereferencing, and error prone when pointer arithmetic is allowed. 774 It is better to have the compiler generate the dereferencing and have no implicit pointer arithmetic: 775 \begin{cfa} 776 p2 = ((p1 + p2) * (p3 - p1)) / (p3 - 15); 777 \end{cfa} 778 779 To support this common case, a reference type is introduced in \CFA, denoted by ©&©, which is the opposite dereference semantics to a pointer type, making the value at the pointed-to location the implicit semantics for dereferencing (similar but not the same as \CC \Index{reference type}s). 780 \begin{cfa} 781 int x, y, ®&® r1, ®&® r2, ®&&® r3; 782 ®&®r1 = &x; §\C{// r1 points to x}§ 783 ®&®r2 = &r1; §\C{// r2 points to x}§ 784 ®&®r1 = &y; §\C{// r1 points to y}§ 785 ®&&®r3 = ®&®&r2; §\C{// r3 points to r2}§ 786 r2 = ((r1 + r2) * (r3 - r1)) / (r3 - 15); §\C{// implicit dereferencing}§ 787 \end{cfa} 788 Except for auto-dereferencing by the compiler, this reference example is the same as the previous pointer example. 789 Hence, a reference behaves like the variable name for the current variable it is pointing-to. 790 One way to conceptualize a reference is via a rewrite rule, where the compiler inserts a dereference operator before the reference variable for each reference qualifier in a declaration, so the previous example becomes: 791 \begin{cfa} 792 ®*®r2 = ((®*®r1 + ®*®r2) ®*® (®**®r3 - ®*®r1)) / (®**®r3 - 15); 793 \end{cfa} 794 When a reference operation appears beside a dereference operation, \eg ©&*©, they cancel out. 795 However, in C, the cancellation always yields a value (\Index{rvalue}).\footnote{ 796 The unary ©&© operator yields the address of its operand. 797 If the operand has type ``type'', the result has type ``pointer to type''. 798 If the operand is the result of a unary ©*© operator, neither that operator nor the ©&© operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue.~\cite[\S~6.5.3.2--3]{C11}} 799 For a \CFA reference type, the cancellation on the left-hand side of assignment leaves the reference as an address (\Index{lvalue}): 800 \begin{cfa} 801 (&®*®)r1 = &x; §\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}§ 802 \end{cfa} 803 Similarly, the address of a reference can be obtained for assignment or computation (\Index{rvalue}): 804 \begin{cfa} 805 (&(&®*®)®*®)r3 = &(&®*®)r2; §\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}§ 806 \end{cfa} 807 Cancellation\index{cancellation!pointer/reference}\index{pointer!cancellation} works to arbitrary depth. 808 809 Fundamentally, pointer and reference objects are functionally interchangeable because both contain addresses. 810 \begin{cfa} 811 int x, *p1 = &x, **p2 = &p1, ***p3 = &p2, 812 &r1 = x, &&r2 = r1, &&&r3 = r2; 813 ***p3 = 3; §\C{// change x}§ 814 r3 = 3; §\C{// change x, ***r3}§ 815 **p3 = ...; §\C{// change p1}§ 816 &r3 = ...; §\C{// change r1, (\&*)**r3, 1 cancellation}§ 817 *p3 = ...; §\C{// change p2}§ 818 &&r3 = ...; §\C{// change r2, (\&(\&*)*)*r3, 2 cancellations}§ 819 &&&r3 = p3; §\C{// change r3 to p3, (\&(\&(\&*)*)*)r3, 3 cancellations}§ 820 \end{cfa} 821 Furthermore, both types are equally performant, as the same amount of dereferencing occurs for both types. 822 Therefore, the choice between them is based solely on whether the address is dereferenced frequently or infrequently, which dictates the amount of implicit dereferencing aid from the compiler. 823 824 As for a pointer type, a reference type may have qualifiers: 825 \begin{cfa} 826 const int cx = 5; §\C{// cannot change cx;}§ 827 const int & cr = cx; §\C{// cannot change what cr points to}§ 828 ®&®cr = &cx; §\C{// can change cr}§ 829 cr = 7; §\C{// error, cannot change cx}§ 830 int & const rc = x; §\C{// must be initialized}§ 831 ®&®rc = &x; §\C{// error, cannot change rc}§ 832 const int & const crc = cx; §\C{// must be initialized}§ 833 crc = 7; §\C{// error, cannot change cx}§ 834 ®&®crc = &cx; §\C{// error, cannot change crc}§ 835 \end{cfa} 836 Hence, for type ©& const©, there is no pointer assignment, so ©&rc = &x© is disallowed, and \emph{the address value cannot be the null pointer unless an arbitrary pointer is coerced\index{coercion} into the reference}: 837 \begin{cfa} 838 int & const cr = *0; §\C{// where 0 is the int * zero}§ 839 \end{cfa} 840 Note, constant reference-types do not prevent \Index{addressing errors} because of explicit storage-management: 841 \begin{cfa} 842 int & const cr = *malloc(); 843 cr = 5; 844 free( &cr ); 845 cr = 7; §\C{// unsound pointer dereference}§ 846 \end{cfa} 847 848 The position of the ©const© qualifier \emph{after} the pointer/reference qualifier causes confuse for C programmers. 849 The ©const© qualifier cannot be moved before the pointer/reference qualifier for C style-declarations; 850 \CFA-style declarations (see \VRef{s:Declarations}) attempt to address this issue: 851 \begin{quote2} 852 \begin{tabular}{@{}l@{\hspace{3em}}l@{}} 853 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 854 \begin{cfa} 855 ®const® * ®const® * const int ccp; 856 ®const® & ®const® & const int ccr; 857 \end{cfa} 858 & 859 \begin{cfa} 860 const int * ®const® * ®const® ccp; 861 862 \end{cfa} 863 \end{tabular} 864 \end{quote2} 865 where the \CFA declaration is read left-to-right. 866 867 Finally, like pointers, references are usable and composable with other type operators and generators. 868 \begin{cfa} 869 int w, x, y, z, & ar[3] = { x, y, z }; §\C{// initialize array of references}§ 870 &ar[1] = &w; §\C{// change reference array element}§ 871 typeof( ar[1] ) p; §\C{// (gcc) is int, i.e., the type of referenced object}§ 872 typeof( &ar[1] ) q; §\C{// (gcc) is int \&, i.e., the type of reference}§ 873 sizeof( ar[1] ) == sizeof( int ); §\C{// is true, i.e., the size of referenced object}§ 874 sizeof( &ar[1] ) == sizeof( int *) §\C{// is true, i.e., the size of a reference}§ 875 \end{cfa} 876 877 In contrast to \CFA reference types, \Index*[C++]{\CC{}}'s reference types are all ©const© references, preventing changes to the reference address, so only value assignment is possible, which eliminates half of the \Index{address duality}. 878 Also, \CC does not allow \Index{array}s\index{array!reference} of reference\footnote{ 879 The reason for disallowing arrays of reference is unknown, but possibly comes from references being ethereal (like a textual macro), and hence, replaceable by the referant object.} 880 \Index*{Java}'s reference types to objects (all Java objects are on the heap) are like C pointers, which always manipulate the address, and there is no (bit-wise) object assignment, so objects are explicitly cloned by shallow or deep copying, which eliminates half of the address duality. 881 882 883 \subsection{Initialization} 884 885 \Index{Initialization} is different than \Index{assignment} because initialization occurs on the empty (uninitialized) storage on an object, while assignment occurs on possibly initialized storage of an object. 886 There are three initialization contexts in \CFA: declaration initialization, argument/parameter binding, return/temporary binding. 887 Because the object being initialized has no value, there is only one meaningful semantics with respect to address duality: it must mean address as there is no pointed-to value. 888 In contrast, the left-hand side of assignment has an address that has a duality. 889 Therefore, for pointer/reference initialization, the initializing value must be an address not a value. 890 \begin{cfa} 891 int * p = &x; §\C{// assign address of x}§ 892 ®int * p = x;® §\C{// assign value of x}§ 893 int & r = x; §\C{// must have address of x}§ 894 \end{cfa} 895 Like the previous example with C pointer-arithmetic, it is unlikely assigning the value of ©x© into a pointer is meaningful (again, a warning is usually given). 896 Therefore, for safety, this context requires an address, so it is superfluous to require explicitly taking the address of the initialization object, even though the type is incorrect. 897 Note, this is strictly a convenience and safety feature for a programmer. 898 Hence, \CFA allows ©r© to be assigned ©x© because it infers a reference for ©x©, by implicitly inserting a address-of operator, ©&©, and it is an error to put an ©&© because the types no longer match due to the implicit dereference. 899 Unfortunately, C allows ©p© to be assigned with ©&x© (address) or ©x© (value), but most compilers warn about the latter assignment as being potentially incorrect. 900 Similarly, when a reference type is used for a parameter/return type, the call-site argument does not require a reference operator for the same reason. 901 \begin{cfa} 902 int & f( int & r ); §\C{// reference parameter and return}§ 903 z = f( x ) + f( y ); §\C{// reference operator added, temporaries needed for call results}§ 904 \end{cfa} 905 Within routine ©f©, it is possible to change the argument by changing the corresponding parameter, and parameter ©r© can be locally reassigned within ©f©. 906 Since operator routine ©?+?© takes its arguments by value, the references returned from ©f© are used to initialize compiler generated temporaries with value semantics that copy from the references. 907 \begin{cfa} 908 int temp1 = f( x ), temp2 = f( y ); 909 z = temp1 + temp2; 910 \end{cfa} 911 This \Index{implicit referencing} is crucial for reducing the syntactic burden for programmers when using references; 912 otherwise references have the same syntactic burden as pointers in these contexts. 913 914 When a pointer/reference parameter has a ©const© value (immutable), it is possible to pass literals and expressions. 915 \begin{cfa} 916 void f( ®const® int & cr ); 917 void g( ®const® int * cp ); 918 f( 3 ); g( ®&®3 ); 919 f( x + y ); g( ®&®(x + y) ); 920 \end{cfa} 921 Here, the compiler passes the address to the literal 3 or the temporary for the expression ©x + y©, knowing the argument cannot be changed through the parameter. 922 The ©&© before the constant/expression for the pointer-type parameter (©g©) is a \CFA extension necessary to type match and is a common requirement before a variable in C (\eg ©scanf©). 923 Importantly, ©&3© may not be equal to ©&3©, where the references occur across calls because the temporaries maybe different on each call. 924 925 \CFA \emph{extends} this semantics to a mutable pointer/reference parameter, and the compiler implicitly creates the necessary temporary (copying the argument), which is subsequently pointed-to by the reference parameter and can be changed.\footnote{ 926 If whole program analysis is possible, and shows the parameter is not assigned, \ie it is ©const©, the temporary is unnecessary.} 927 \begin{cfa} 928 void f( int & r ); 929 void g( int * p ); 930 f( 3 ); g( ®&®3 ); §\C{// compiler implicit generates temporaries}§ 931 f( x + y ); g( ®&®(x + y) ); §\C{// compiler implicit generates temporaries}§ 932 \end{cfa} 933 Essentially, there is an implicit \Index{rvalue} to \Index{lvalue} conversion in this case.\footnote{ 934 This conversion attempts to address the \newterm{const hell} problem, when the innocent addition of a ©const© qualifier causes a cascade of type failures, requiring an unknown number of additional ©const© qualifiers, until it is discovered a ©const© qualifier cannot be added and all the ©const© qualifiers must be removed.} 935 The implicit conversion allows seamless calls to any routine without having to explicitly name/copy the literal/expression to allow the call. 936 937 %\CFA attempts to handle pointers and references in a uniform, symmetric manner. 938 Finally, C handles \Index{routine object}s in an inconsistent way. 939 A routine object is both a pointer and a reference (\Index{particle and wave}). 940 \begin{cfa} 941 void f( int i ); 942 void (*fp)( int ); §\C{// routine pointer}§ 943 fp = f; §\C{// reference initialization}§ 944 fp = &f; §\C{// pointer initialization}§ 945 fp = *f; §\C{// reference initialization}§ 946 fp(3); §\C{// reference invocation}§ 947 (*fp)(3); §\C{// pointer invocation}§ 948 \end{cfa} 949 While C's treatment of routine objects has similarity to inferring a reference type in initialization contexts, the examples are assignment not initialization, and all possible forms of assignment are possible (©f©, ©&f©, ©*f©) without regard for type. 950 Instead, a routine object should be referenced by a ©const© reference: 951 \begin{cfa} 952 ®const® void (®&® fr)( int ) = f; §\C{// routine reference}§ 953 fr = ... §\C{// error, cannot change code}§ 954 &fr = ...; §\C{// changing routine reference}§ 955 fr( 3 ); §\C{// reference call to f}§ 956 (*fr)(3); §\C{// error, incorrect type}§ 957 \end{cfa} 958 because the value of the routine object is a routine literal, \ie the routine code is normally immutable during execution.\footnote{ 959 Dynamic code rewriting is possible but only in special circumstances.} 960 \CFA allows this additional use of references for routine objects in an attempt to give a more consistent meaning for them. 961 962 963 \subsection{Address-of Semantics} 964 965 In C, ©&E© is an rvalue for any expression ©E©. 966 \CFA extends the ©&© (address-of) operator as follows: 967 \begin{itemize} 968 \item 969 if ©R© is an \Index{rvalue} of type ©T &$_1$...&$_r$© where $r \ge 1$ references (©&© symbols) than ©&R© has type ©T ®*®&$_{\color{red}2}$...&$_{\color{red}r}$©, \ie ©T© pointer with $r-1$ references (©&© symbols). 970 971 \item 972 if ©L© is an \Index{lvalue} of type ©T &$_1$...&$_l$© where $l \ge 0$ references (©&© symbols) then ©&L© has type ©T ®*®&$_{\color{red}1}$...&$_{\color{red}l}$©, \ie ©T© pointer with $l$ references (©&© symbols). 973 \end{itemize} 974 The following example shows the first rule applied to different \Index{rvalue} contexts: 975 \begin{cfa} 976 int x, * px, ** ppx, *** pppx, **** ppppx; 977 int & rx = x, && rrx = rx, &&& rrrx = rrx ; 978 x = rrrx; // rrrx is an lvalue with type int &&& (equivalent to x) 979 px = &rrrx; // starting from rrrx, &rrrx is an rvalue with type int *&&& (&x) 980 ppx = &&rrrx; // starting from &rrrx, &&rrrx is an rvalue with type int **&& (&rx) 981 pppx = &&&rrrx; // starting from &&rrrx, &&&rrrx is an rvalue with type int ***& (&rrx) 982 ppppx = &&&&rrrx; // starting from &&&rrrx, &&&&rrrx is an rvalue with type int **** (&rrrx) 983 \end{cfa} 984 The following example shows the second rule applied to different \Index{lvalue} contexts: 985 \begin{cfa} 986 int x, * px, ** ppx, *** pppx; 987 int & rx = x, && rrx = rx, &&& rrrx = rrx ; 988 rrrx = 2; // rrrx is an lvalue with type int &&& (equivalent to x) 989 &rrrx = px; // starting from rrrx, &rrrx is an rvalue with type int *&&& (rx) 990 &&rrrx = ppx; // starting from &rrrx, &&rrrx is an rvalue with type int **&& (rrx) 991 &&&rrrx = pppx; // starting from &&rrrx, &&&rrrx is an rvalue with type int ***& (rrrx) 992 \end{cfa} 993 994 995 \subsection{Conversions} 996 997 C provides a basic implicit conversion to simplify variable usage: 998 \begin{enumerate} 999 \setcounter{enumi}{-1} 1000 \item 1001 lvalue to rvalue conversion: ©cv T© converts to ©T©, which allows implicit variable dereferencing. 1002 \begin{cfa} 1003 int x; 1004 x + 1; // lvalue variable (int) converts to rvalue for expression 1005 \end{cfa} 1006 An rvalue has no type qualifiers (©cv©), so the lvalue qualifiers are dropped. 1007 \end{enumerate} 1008 \CFA provides three new implicit conversion for reference types to simplify reference usage. 1009 \begin{enumerate} 1010 \item 1011 reference to rvalue conversion: ©cv T &© converts to ©T©, which allows implicit reference dereferencing. 1012 \begin{cfa} 1013 int x, &r = x, f( int p ); 1014 x = ®r® + f( ®r® ); // lvalue reference converts to rvalue 1015 \end{cfa} 1016 An rvalue has no type qualifiers (©cv©), so the reference qualifiers are dropped. 1017 1018 \item 1019 lvalue to reference conversion: \lstinline[deletekeywords={lvalue}]@lvalue-type cv1 T@ converts to ©cv2 T &©, which allows implicitly converting variables to references. 1020 \begin{cfa} 1021 int x, &r = ®x®, f( int & p ); // lvalue variable (int) convert to reference (int &) 1022 f( ®x® ); // lvalue variable (int) convert to reference (int &) 1023 \end{cfa} 1024 Conversion can restrict a type, where ©cv1© $\le$ ©cv2©, \eg passing an ©int© to a ©const volatile int &©, which has low cost. 1025 Conversion can expand a type, where ©cv1© $>$ ©cv2©, \eg passing a ©const volatile int© to an ©int &©, which has high cost (\Index{warning}); 1026 furthermore, if ©cv1© has ©const© but not ©cv2©, a temporary variable is created to preserve the immutable lvalue. 1027 1028 \item 1029 rvalue to reference conversion: ©T© converts to ©cv T &©, which allows binding references to temporaries. 1030 \begin{cfa} 1031 int x, & f( int & p ); 1032 f( ®x + 3® ); // rvalue parameter (int) implicitly converts to lvalue temporary reference (int &) 1033 ®&f®(...) = &x; // rvalue result (int &) implicitly converts to lvalue temporary reference (int &) 1034 \end{cfa} 1035 In both case, modifications to the temporary are inaccessible (\Index{warning}). 1036 Conversion expands the temporary-type with ©cv©, which is low cost since the temporary is inaccessible. 1037 \end{enumerate} 1038 1039 1040 \begin{comment} 1041 From: Richard Bilson <rcbilson@gmail.com> 1042 Date: Wed, 13 Jul 2016 01:58:58 +0000 1043 Subject: Re: pointers / references 1044 To: "Peter A. Buhr" <pabuhr@plg2.cs.uwaterloo.ca> 1045 1046 As a general comment I would say that I found the section confusing, as you move back and forth 1047 between various real and imagined programming languages. If it were me I would rewrite into two 1048 subsections, one that specifies precisely the syntax and semantics of reference variables and 1049 another that provides the rationale. 1050 1051 I don't see any obvious problems with the syntax or semantics so far as I understand them. It's not 1052 obvious that the description you're giving is complete, but I'm sure you'll find the special cases 1053 as you do the implementation. 1054 1055 My big gripes are mostly that you're not being as precise as you need to be in your terminology, and 1056 that you say a few things that aren't actually true even though I generally know what you mean. 1057 1058 20 C provides a pointer type; CFA adds a reference type. Both types contain an address, which is normally a 1059 21 location in memory. 1060 1061 An address is not a location in memory; an address refers to a location in memory. Furthermore it 1062 seems weird to me to say that a type "contains" an address; rather, objects of that type do. 1063 1064 21 Special addresses are used to denote certain states or access co-processor memory. By 1065 22 convention, no variable is placed at address 0, so addresses like 0, 1, 2, 3 are often used to denote no-value 1066 23 or other special states. 1067 1068 This isn't standard C at all. There has to be one null pointer representation, but it doesn't have 1069 to be a literal zero representation and there doesn't have to be more than one such representation. 1070 1071 23 Often dereferencing a special state causes a memory fault, so checking is necessary 1072 24 during execution. 1073 1074 I don't see the connection between the two clauses here. I feel like if a bad pointer will not cause 1075 a memory fault then I need to do more checking, not less. 1076 1077 24 If the programming language assigns addresses, a program's execution is sound, \ie all 1078 25 addresses are to valid memory locations. 1079 1080 You haven't said what it means to "assign" an address, but if I use my intuitive understanding of 1081 the term I don't see how this can be true unless you're assuming automatic storage management. 1082 1083 1 Program variables are implicit pointers to memory locations generated by the compiler and automatically 1084 2 dereferenced, as in: 1085 1086 There is no reason why a variable needs to have a location in memory, and indeed in a typical 1087 program many variables will not. In standard terminology an object identifier refers to data in the 1088 execution environment, but not necessarily in memory. 1089 1090 13 A pointer/reference is a generalization of a variable name, \ie a mutable address that can point to more 1091 14 than one memory location during its lifetime. 1092 1093 I feel like you're off the reservation here. In my world there are objects of pointer type, which 1094 seem to be what you're describing here, but also pointer values, which can be stored in an object of 1095 pointer type but don't necessarily have to be. For example, how would you describe the value denoted 1096 by "&main" in a C program? I would call it a (function) pointer, but that doesn't satisfy your 1097 definition. 1098 1099 16 not occupy storage as the literal is embedded directly into instructions.) Hence, a pointer occupies memory 1100 17 to store its current address, and the pointer's value is loaded by dereferencing, e.g.: 1101 1102 As with my general objection regarding your definition of variables, there is no reason why a 1103 pointer variable (object of pointer type) needs to occupy memory. 1104 1105 21 p2 = p1 + x; // compiler infers *p2 = *p1 + x; 1106 1107 What language are we in now? 1108 1109 24 pointer usage. However, in C, the following cases are ambiguous, especially with pointer arithmetic: 1110 25 p1 = p2; // p1 = p2 or *p1 = *p2 1111 1112 This isn't ambiguous. it's defined to be the first option. 1113 1114 26 p1 = p1 + 1; // p1 = p1 + 1 or *p1 = *p1 + 1 1115 1116 Again, this statement is not ambiguous. 1117 1118 13 example. Hence, a reference behaves like the variable name for the current variable it is pointing-to. The 1119 14 simplest way to understand a reference is to imagine the compiler inserting a dereference operator before 1120 15 the reference variable for each reference qualifier in a declaration, e.g.: 1121 1122 It's hard for me to understand who the audience for this part is. I think a practical programmer is 1123 likely to be satisfied with "a reference behaves like the variable name for the current variable it 1124 is pointing-to," maybe with some examples. Your "simplest way" doesn't strike me as simpler than 1125 that. It feels like you're trying to provide a more precise definition for the semantics of 1126 references, but it isn't actually precise enough to be a formal specification. If you want to 1127 express the semantics of references using rewrite rules that's a great way to do it, but lay the 1128 rules out clearly, and when you're showing an example of rewriting keep your 1129 references/pointers/values separate (right now, you use \eg "r3" to mean a reference, a pointer, 1130 and a value). 1131 1132 24 Cancellation works to arbitrary depth, and pointer and reference values are interchangeable because both 1133 25 contain addresses. 1134 1135 Except they're not interchangeable, because they have different and incompatible types. 1136 1137 40 Interestingly, C++ deals with the address duality by making the pointed-to value the default, and prevent- 1138 41 ing changes to the reference address, which eliminates half of the duality. Java deals with the address duality 1139 42 by making address assignment the default and requiring field assignment (direct or indirect via methods), 1140 43 \ie there is no builtin bit-wise or method-wise assignment, which eliminates half of the duality. 1141 1142 I can follow this but I think that's mostly because I already understand what you're trying to 1143 say. I don't think I've ever heard the term "method-wise assignment" and I don't see you defining 1144 it. Furthermore Java does have value assignment of basic (non-class) types, so your summary here 1145 feels incomplete. (If it were me I'd drop this paragraph rather than try to save it.) 1146 1147 11 Hence, for type & const, there is no pointer assignment, so &rc = &x is disallowed, and the address value 1148 12 cannot be 0 unless an arbitrary pointer is assigned to the reference. 1149 1150 Given the pains you've taken to motivate every little bit of the semantics up until now, this last 1151 clause ("the address value cannot be 0") comes out of the blue. It seems like you could have 1152 perfectly reasonable semantics that allowed the initialization of null references. 1153 1154 12 In effect, the compiler is managing the 1155 13 addresses for type & const not the programmer, and by a programming discipline of only using references 1156 14 with references, address errors can be prevented. 1157 1158 Again, is this assuming automatic storage management? 1159 1160 18 rary binding. For reference initialization (like pointer), the initializing value must be an address (lvalue) not 1161 19 a value (rvalue). 1162 1163 This sentence appears to suggest that an address and an lvalue are the same thing. 1164 1165 20 int * p = &x; // both &x and x are possible interpretations 1166 1167 Are you saying that we should be considering "x" as a possible interpretation of the initializer 1168 "&x"? It seems to me that this expression has only one legitimate interpretation in context. 1169 1170 21 int & r = x; // x unlikely interpretation, because of auto-dereferencing 1171 1172 You mean, we can initialize a reference using an integer value? Surely we would need some sort of 1173 cast to induce that interpretation, no? 1174 1175 22 Hence, the compiler implicitly inserts a reference operator, &, before the initialization expression. 1176 1177 But then the expression would have pointer type, which wouldn't be compatible with the type of r. 1178 1179 22 Similarly, 1180 23 when a reference is used for a parameter/return type, the call-site argument does not require a reference 1181 24 operator. 1182 1183 Furthermore, it would not be correct to use a reference operator. 1184 1185 45 The implicit conversion allows 1186 1 seamless calls to any routine without having to explicitly name/copy the literal/expression to allow the call. 1187 2 While C' attempts to handle pointers and references in a uniform, symmetric manner, C handles routine 1188 3 variables in an inconsistent way: a routine variable is both a pointer and a reference (particle and wave). 1189 1190 After all this talk of how expressions can have both pointer and value interpretations, you're 1191 disparaging C because it has expressions that have both pointer and value interpretations? 1192 1193 On Sat, Jul 9, 2016 at 4:18 PM Peter A. Buhr <pabuhr@plg.uwaterloo.ca> wrote: 1194 > Aaron discovered a few places where "&"s are missing and where there are too many "&", which are 1195 > corrected in the attached updated. None of the text has changed, if you have started reading 1196 > already. 1197 \end{comment} 1198 1199 1200 \section{Routine Definition} 1201 1202 \CFA also supports a new syntax for routine definition, as well as \Celeven and K\&R routine syntax. 1203 The point of the new syntax is to allow returning multiple values from a routine~\cite{Galletly96,CLU}, \eg: 1204 \begin{cfa} 1205 ®[ int o1, int o2, char o3 ]® f( int i1, char i2, char i3 ) { 1206 §\emph{routine body}§ 1207 } 1208 \end{cfa} 1209 where routine ©f© has three output (return values) and three input parameters. 1210 Existing C syntax cannot be extended with multiple return types because it is impossible to embed a single routine name within multiple return type specifications. 1211 1212 In detail, the brackets, ©[]©, enclose the result type, where each return value is named and that name is a local variable of the particular return type.\footnote{ 1213 \Index*{Michael Tiemann}, with help from \Index*{Doug Lea}, provided named return values in g++, circa 1989.} 1214 The value of each local return variable is automatically returned at routine termination. 1215 Declaration qualifiers can only appear at the start of a routine definition, \eg: 1216 \begin{cfa} 1217 ®extern® [ int x ] g( int y ) {§\,§} 1218 \end{cfa} 1219 Lastly, if there are no output parameters or input parameters, the brackets and/or parentheses must still be specified; 1220 in both cases the type is assumed to be void as opposed to old style C defaults of int return type and unknown parameter types, respectively, as in: 1221 \begin{cfa} 1222 [§\,§] g(); §\C{// no input or output parameters}§ 1223 [ void ] g( void ); §\C{// no input or output parameters}§ 1224 \end{cfa} 1225 1226 Routine f is called as follows: 1227 \begin{cfa} 1228 [ i, j, ch ] = f( 3, 'a', ch ); 1229 \end{cfa} 1230 The list of return values from f and the grouping on the left-hand side of the assignment is called a \newterm{return list} and discussed in Section 12. 1231 1232 \CFA style declarations cannot be used to declare parameters for K\&R style routine definitions because of the following ambiguity: 1233 \begin{cfa} 1234 int (*f(x))[ 5 ] int x; {} 1235 \end{cfa} 1236 The string ``©int (*f(x))[ 5 ]©'' declares a K\&R style routine of type returning a pointer to an array of 5 integers, while the string ``©[ 5 ] int x©'' declares a \CFA style parameter x of type array of 5 integers. 1237 Since the strings overlap starting with the open bracket, ©[©, there is an ambiguous interpretation for the string. 1238 As well, \CFA-style declarations cannot be used to declare parameters for C-style routine-definitions because of the following ambiguity: 1239 \begin{cfa} 1240 typedef int foo; 1241 int f( int (* foo) ); §\C{// foo is redefined as a parameter name}§ 1242 \end{cfa} 1243 The string ``©int (* foo)©'' declares a C-style named-parameter of type pointer to an integer (the parenthesis are superfluous), while the same string declares a \CFA style unnamed parameter of type routine returning integer with unnamed parameter of type pointer to foo. 1244 The redefinition of a type name in a parameter list is the only context in C where the character ©*© can appear to the left of a type name, and \CFA relies on all type qualifier characters appearing to the right of the type name. 1245 The inability to use \CFA declarations in these two contexts is probably a blessing because it precludes programmers from arbitrarily switching between declarations forms within a declaration contexts. 1246 1247 C-style declarations can be used to declare parameters for \CFA style routine definitions, \eg: 1248 \begin{cfa} 1249 [ int ] f( * int, int * ); §\C{// returns an integer, accepts 2 pointers to integers}§ 1250 [ * int, int * ] f( int ); §\C{// returns 2 pointers to integers, accepts an integer}§ 1251 \end{cfa} 1252 The reason for allowing both declaration styles in the new context is for backwards compatibility with existing preprocessor macros that generate C-style declaration-syntax, as in: 1253 \begin{cfa} 1254 #define ptoa( n, d ) int (*n)[ d ] 1255 int f( ptoa( p, 5 ) ) ... §\C{// expands to int f( int (*p)[ 5 ] )}§ 1256 [ int ] f( ptoa( p, 5 ) ) ... §\C{// expands to [ int ] f( int (*p)[ 5 ] )}§ 1257 \end{cfa} 1258 Again, programmers are highly encouraged to use one declaration form or the other, rather than mixing the forms. 1259 1260 1261 \subsection{Named Return Values} 1262 1263 \Index{Named return values} handle the case where it is necessary to define a local variable whose value is then returned in a ©return© statement, as in: 1264 \begin{cfa} 1265 int f() { 1266 int x; 1267 ... x = 0; ... x = y; ... 1268 return x; 1269 } 1270 \end{cfa} 1271 Because the value in the return variable is automatically returned when a \CFA routine terminates, the ©return© statement \emph{does not} contain an expression, as in: 1272 \newline 1273 \begin{minipage}{\linewidth} 1274 \begin{cfa} 1275 ®[ int x, int y ]® f() { 1276 int z; 1277 ... x = 0; ... y = z; ... 1278 ®return;® §\C{// implicitly return x, y}§ 1279 } 1280 \end{cfa} 1281 \end{minipage} 1282 \newline 1283 When the return is encountered, the current values of ©x© and ©y© are returned to the calling routine. 1284 As well, ``falling off the end'' of a routine without a ©return© statement is permitted, as in: 1285 \begin{cfa} 1286 [ int x, int y ] f() { 1287 ... 1288 } §\C{// implicitly return x, y}§ 1289 \end{cfa} 1290 In this case, the current values of ©x© and ©y© are returned to the calling routine just as if a ©return© had been encountered. 1291 1292 Named return values may be used in conjunction with named parameter values; 1293 specifically, a return and parameter can have the same name. 1294 \begin{cfa} 1295 [ int x, int y ] f( int, x, int y ) { 1296 ... 1297 } §\C{// implicitly return x, y}§ 1298 \end{cfa} 1299 This notation allows the compiler to eliminate temporary variables in nested routine calls. 1300 \begin{cfa} 1301 [ int x, int y ] f( int, x, int y ); §\C{// prototype declaration}§ 1302 int a, b; 1303 [a, b] = f( f( f( a, b ) ) ); 1304 \end{cfa} 1305 While the compiler normally ignores parameters names in prototype declarations, here they are used to eliminate temporary return-values by inferring that the results of each call are the inputs of the next call, and ultimately, the left-hand side of the assignment. 1306 Hence, even without the body of routine ©f© (separate compilation), it is possible to perform a global optimization across routine calls. 1307 The compiler warns about naming inconsistencies between routine prototype and definition in this case, and behaviour is \Index{undefined} if the programmer is inconsistent. 1308 1309 1310 \subsection{Routine Prototype} 1311 1312 The syntax of the new routine prototype declaration follows directly from the new routine definition syntax; 1313 as well, parameter names are optional, \eg: 1314 \begin{cfa} 1315 [ int x ] f (); §\C{// returning int with no parameters}§ 1316 [ * int ] g (int y); §\C{// returning pointer to int with int parameter}§ 1317 [ ] h ( int, char ); §\C{// returning no result with int and char parameters}§ 1318 [ * int, int ] j ( int ); §\C{// returning pointer to int and int, with int parameter}§ 1319 \end{cfa} 1320 This syntax allows a prototype declaration to be created by cutting and pasting source text from the routine definition header (or vice versa). 1321 It is possible to declare multiple routine-prototypes in a single declaration, but the entire type specification is distributed across \emph{all} routine names in the declaration list (see~\VRef{s:Declarations}), \eg: 1322 \begin{quote2} 1323 \begin{tabular}{@{}l@{\hspace{3em}}l@{}} 1324 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1325 \begin{cfa} 1326 [ int ] f( int ), g; 1327 \end{cfa} 1328 & 1329 \begin{cfa} 1330 int f( int ), g( int ); 1331 \end{cfa} 1332 \end{tabular} 1333 \end{quote2} 1334 Declaration qualifiers can only appear at the start of a \CFA routine declaration,\footref{StorageClassSpecifier} \eg: 1335 \begin{cfa} 1336 extern [ int ] f ( int ); 1337 static [ int ] g ( int ); 1338 \end{cfa} 1339 1340 1341 \section{Routine Pointers} 1342 1343 The syntax for pointers to \CFA routines specifies the pointer name on the right, \eg: 1344 \begin{cfa} 1345 * [ int x ] () fp; §\C{// pointer to routine returning int with no parameters}§ 1346 * [ * int ] (int y) gp; §\C{// pointer to routine returning pointer to int with int parameter}§ 1347 * [ ] (int,char) hp; §\C{// pointer to routine returning no result with int and char parameters}§ 1348 * [ * int,int ] ( int ) jp; §\C{// pointer to routine returning pointer to int and int, with int parameter}§ 1349 \end{cfa} 1350 While parameter names are optional, \emph{a routine name cannot be specified}; 1351 for example, the following is incorrect: 1352 \begin{cfa} 1353 * [ int x ] f () fp; §\C{// routine name "f" is not allowed}§ 1354 \end{cfa} 1355 1356 1357 \section{Named and Default Arguments} 1358 1359 Named\index{named arguments}\index{arguments!named} and default\index{default arguments}\index{arguments!default} arguments~\cite{Hardgrave76}\footnote{ 1360 Francez~\cite{Francez77} proposed a further extension to the named-parameter passing style, which specifies what type of communication (by value, by reference, by name) the argument is passed to the routine.} 1361 are two mechanisms to simplify routine call. 1362 Both mechanisms are discussed with respect to \CFA. 1363 \begin{description} 1364 \item[Named (or Keyword) Arguments:] 1365 provide the ability to specify an argument to a routine call using the parameter name rather than the position of the parameter. 1366 For example, given the routine: 1367 \begin{cfa} 1368 void p( int x, int y, int z ) {...} 1369 \end{cfa} 1370 a positional call is: 1371 \begin{cfa} 1372 p( 4, 7, 3 ); 1373 \end{cfa} 1374 whereas a named (keyword) call may be: 1375 \begin{cfa} 1376 p( z : 3, x : 4, y : 7 ); §\C{// rewrite $\Rightarrow$ p( 4, 7, 3 )}§ 1377 \end{cfa} 1378 Here the order of the arguments is unimportant, and the names of the parameters are used to associate argument values with the corresponding parameters. 1379 The compiler rewrites a named call into a positional call. 1380 The advantages of named parameters are: 1381 \begin{itemize} 1382 \item 1383 Remembering the names of the parameters may be easier than the order in the routine definition. 1384 \item 1385 Parameter names provide documentation at the call site (assuming the names are descriptive). 1386 \item 1387 Changes can be made to the order or number of parameters without affecting the call (although the call must still be recompiled). 1388 \end{itemize} 1389 1390 Unfortunately, named arguments do not work in C-style programming-languages because a routine prototype is not required to specify parameter names, nor do the names in the prototype have to match with the actual definition. 1391 For example, the following routine prototypes and definition are all valid. 1392 \begin{cfa} 1393 void p( int, int, int ); §\C{// equivalent prototypes}§ 1394 void p( int x, int y, int z ); 1395 void p( int y, int x, int z ); 1396 void p( int z, int y, int x ); 1397 void p( int q, int r, int s ) {} §\C{// match with this definition}§ 1398 \end{cfa} 1399 Forcing matching parameter names in routine prototypes with corresponding routine definitions is possible, but goes against a strong tradition in C programming. 1400 Alternatively, prototype definitions can be eliminated by using a two-pass compilation, and implicitly creating header files for exports. 1401 The former is easy to do, while the latter is more complex. 1402 1403 Furthermore, named arguments do not work well in a \CFA-style programming-languages because they potentially introduces a new criteria for type matching. 1404 For example, it is technically possible to disambiguate between these two overloaded definitions of ©f© based on named arguments at the call site: 1405 \begin{cfa} 1406 int f( int i, int j ); 1407 int f( int x, double y ); 1408 1409 f( j : 3, i : 4 ); §\C{// 1st f}§ 1410 f( x : 7, y : 8.1 ); §\C{// 2nd f}§ 1411 f( 4, 5 ); §\C{// ambiguous call}§ 1412 \end{cfa} 1413 However, named arguments compound routine resolution in conjunction with conversions: 1414 \begin{cfa} 1415 f( i : 3, 5.7 ); §\C{// ambiguous call ?}§ 1416 \end{cfa} 1417 Depending on the cost associated with named arguments, this call could be resolvable or ambiguous. 1418 Adding named argument into the routine resolution algorithm does not seem worth the complexity. 1419 Therefore, \CFA does \emph{not} attempt to support named arguments. 1420 1421 \item[Default Arguments] 1422 provide the ability to associate a default value with a parameter so it can be optionally specified in the argument list. 1423 For example, given the routine: 1424 \begin{cfa} 1425 void p( int x = 1, int y = 2, int z = 3 ) {...} 1426 \end{cfa} 1427 the allowable positional calls are: 1428 \begin{cfa} 1429 p(); §\C{// rewrite $\Rightarrow$ p( 1, 2, 3 )}§ 1430 p( 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 2, 3 )}§ 1431 p( 4, 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 4, 3 )}§ 1432 p( 4, 4, 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 4, 4 )}§ 1433 // empty arguments 1434 p( , 4, 4 ); §\C{// rewrite $\Rightarrow$ p( 1, 4, 4 )}§ 1435 p( 4, , 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 2, 4 )}§ 1436 p( 4, 4, ); §\C{// rewrite $\Rightarrow$ p( 4, 4, 3 )}§ 1437 p( 4, , ); §\C{// rewrite $\Rightarrow$ p( 4, 2, 3 )}§ 1438 p( , 4, ); §\C{// rewrite $\Rightarrow$ p( 1, 4, 3 )}§ 1439 p( , , 4 ); §\C{// rewrite $\Rightarrow$ p( 1, 2, 4 )}§ 1440 p( , , ); §\C{// rewrite $\Rightarrow$ p( 1, 2, 3 )}§ 1441 \end{cfa} 1442 Here the missing arguments are inserted from the default values in the parameter list. 1443 The compiler rewrites missing default values into explicit positional arguments. 1444 The advantages of default values are: 1445 \begin{itemize} 1446 \item 1447 Routines with a large number of parameters are often very generalized, giving a programmer a number of different options on how a computation is performed. 1448 For many of these kinds of routines, there are standard or default settings that work for the majority of computations. 1449 Without default values for parameters, a programmer is forced to specify these common values all the time, resulting in long argument lists that are error prone. 1450 \item 1451 When a routine's interface is augmented with new parameters, it extends the interface providing generalizability\footnote{ 1452 ``It should be possible for the implementor of an abstraction to increase its generality. 1453 So long as the modified abstraction is a generalization of the original, existing uses of the abstraction will not require change. 1454 It might be possible to modify an abstraction in a manner which is not a generalization without affecting existing uses, but, without inspecting the modules in which the uses occur, this possibility cannot be determined. 1455 This criterion precludes the addition of parameters, unless these parameters have default or inferred values that are valid for all possible existing applications.''~\cite[p.~128]{Cormack90}} 1456 (somewhat like the generalization provided by inheritance for classes). 1457 That is, all existing calls are still valid, although the call must still be recompiled. 1458 \end{itemize} 1459 The only disadvantage of default arguments is that unintentional omission of an argument may not result in a compiler-time error. 1460 Instead, a default value is used, which may not be the programmer's intent. 1461 1462 Default values may only appear in a prototype versus definition context: 1463 \begin{cfa} 1464 void p( int x, int y = 2, int z = 3 ); §\C{// prototype: allowed}§ 1465 void p( int, int = 2, int = 3 ); §\C{// prototype: allowed}§ 1466 void p( int x, int y = 2, int z = 3 ) {} §\C{// definition: not allowed}§ 1467 \end{cfa} 1468 The reason for this restriction is to allow separate compilation. 1469 Multiple prototypes with different default values is an error. 1470 \end{description} 1471 1472 Ellipse (``...'') arguments present problems when used with default arguments. 1473 The conflict occurs because both named and ellipse arguments must appear after positional arguments, giving two possibilities: 1474 \begin{cfa} 1475 p( /* positional */, ... , /* named */ ); 1476 p( /* positional */, /* named */, ... ); 1477 \end{cfa} 1478 While it is possible to implement both approaches, the first possibly is more complex than the second, \eg: 1479 \begin{cfa} 1480 p( int x, int y, int z, ... ); 1481 p( 1, 4, 5, 6, z : 3, y : 2 ); §\C{// assume p( /* positional */, ... , /* named */ );}§ 1482 p( 1, z : 3, y : 2, 4, 5, 6 ); §\C{// assume p( /* positional */, /* named */, ... );}§ 1483 \end{cfa} 1484 In the first call, it is necessary for the programmer to conceptually rewrite the call, changing named arguments into positional, before knowing where the ellipse arguments begin. 1485 Hence, this approach seems significantly more difficult, and hence, confusing and error prone. 1486 In the second call, the named arguments separate the positional and ellipse arguments, making it trivial to read the call. 1487 1488 The problem is exacerbated with default arguments, \eg: 1489 \begin{cfa} 1490 void p( int x, int y = 2, int z = 3... ); 1491 p( 1, 4, 5, 6, z : 3 ); §\C{// assume p( /* positional */, ... , /* named */ );}§ 1492 p( 1, z : 3, 4, 5, 6 ); §\C{// assume p( /* positional */, /* named */, ... );}§ 1493 \end{cfa} 1494 The first call is an error because arguments 4 and 5 are actually positional not ellipse arguments; 1495 therefore, argument 5 subsequently conflicts with the named argument z : 3. 1496 In the second call, the default value for y is implicitly inserted after argument 1 and the named arguments separate the positional and ellipse arguments, making it trivial to read the call. 1497 For these reasons, \CFA requires named arguments before ellipse arguments. 1498 Finally, while ellipse arguments are needed for a small set of existing C routines, like printf, the extended \CFA type system largely eliminates the need for ellipse arguments (see Section 24), making much of this discussion moot. 1499 1500 Default arguments and overloading (see Section 24) are complementary. 1501 While in theory default arguments can be simulated with overloading, as in: 1502 \begin{quote2} 1503 \begin{tabular}{@{}l@{\hspace{3em}}l@{}} 1504 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{default arguments}} & \multicolumn{1}{c}{\textbf{overloading}} \\ 1505 \begin{cfa} 1506 void p( int x, int y = 2, int z = 3 ) {...} 1507 1508 1509 \end{cfa} 1510 & 1511 \begin{cfa} 1512 void p( int x, int y, int z ) {...} 1513 void p( int x ) { p( x, 2, 3 ); } 1514 void p( int x, int y ) { p( x, y, 3 ); } 1515 \end{cfa} 1516 \end{tabular} 1517 \end{quote2} 1518 the number of required overloaded routines is linear in the number of default values, which is unacceptable growth. 1519 In general, overloading should only be used over default arguments if the body of the routine is significantly different. 1520 Furthermore, overloading cannot handle accessing default arguments in the middle of a positional list, via a missing argument, such as: 1521 \begin{cfa} 1522 p( 1, /* default */, 5 ); §\C{// rewrite $\Rightarrow$ p( 1, 2, 5 )}§ 1523 \end{cfa} 1524 1525 Given the \CFA restrictions above, both named and default arguments are backwards compatible. 1526 \Index*[C++]{\CC{}} only supports default arguments; 1527 \Index*{Ada} supports both named and default arguments. 1528 1529 1530 \section{Unnamed Structure Fields} 1531 1532 C requires each field of a structure to have a name, except for a bit field associated with a basic type, \eg: 1533 \begin{cfa} 1534 struct { 1535 int f1; §\C{// named field}§ 1536 int f2 : 4; §\C{// named field with bit field size}§ 1537 int : 3; §\C{// unnamed field for basic type with bit field size}§ 1538 int ; §\C{// disallowed, unnamed field}§ 1539 int *; §\C{// disallowed, unnamed field}§ 1540 int (*)( int ); §\C{// disallowed, unnamed field}§ 1541 }; 1542 \end{cfa} 1543 This requirement is relaxed by making the field name optional for all field declarations; therefore, all the field declarations in the example are allowed. 1544 As for unnamed bit fields, an unnamed field is used for padding a structure to a particular size. 1545 A list of unnamed fields is also supported, \eg: 1546 \begin{cfa} 1547 struct { 1548 int , , ; §\C{// 3 unnamed fields}§ 1549 } 1550 \end{cfa} 1551 1552 1553 \section{Nesting} 1554 1555 Nesting of types and routines is useful for controlling name visibility (\newterm{name hiding}). 1556 1557 1558 \subsection{Type Nesting} 1559 1560 \CFA allows \Index{type nesting}, and type qualification of the nested types (see \VRef[Figure]{f:TypeNestingQualification}), where as C hoists\index{type hoisting} (refactors) nested types into the enclosing scope and has no type qualification. 1561 \begin{figure} 1562 \centering 1563 \begin{tabular}{@{}l@{\hspace{3em}}l|l@{}} 1564 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{C Type Nesting}} & \multicolumn{1}{c}{\textbf{C Implicit Hoisting}} & \multicolumn{1}{|c}{\textbf{\CFA}} \\ 1565 \hline 1566 \begin{cfa} 1567 struct S { 1568 enum C { R, G, B }; 1569 struct T { 1570 union U { int i, j; }; 1571 enum C c; 1572 short int i, j; 1573 }; 1574 struct T t; 1575 } s; 1576 1577 int fred() { 1578 s.t.c = R; 1579 struct T t = { R, 1, 2 }; 1580 enum C c; 1581 union U u; 1582 } 1583 \end{cfa} 1584 & 1585 \begin{cfa} 1586 enum C { R, G, B }; 1587 union U { int i, j; }; 1588 struct T { 1589 enum C c; 1590 short int i, j; 1591 }; 1592 struct S { 1593 struct T t; 1594 } s; 1595 1596 1597 1598 1599 1600 1601 1602 \end{cfa} 1603 & 1604 \begin{cfa} 1605 struct S { 1606 enum C { R, G, B }; 1607 struct T { 1608 union U { int i, j; }; 1609 enum C c; 1610 short int i, j; 1611 }; 1612 struct T t; 1613 } s; 1614 1615 int fred() { 1616 s.t.c = ®S.®R; // type qualification 1617 struct ®S.®T t = { ®S.®R, 1, 2 }; 1618 enum ®S.®C c; 1619 union ®S.T.®U u; 1620 } 1621 \end{cfa} 1622 \end{tabular} 1623 \caption{Type Nesting / Qualification} 1624 \label{f:TypeNestingQualification} 1625 \end{figure} 1626 In the left example in C, types ©C©, ©U© and ©T© are implicitly hoisted outside of type ©S© into the containing block scope. 1627 In the right example in \CFA, the types are not hoisted and accessed using the field-selection operator ``©.©'' for type qualification, as does \Index*{Java}, rather than the \CC type-selection operator ``©::©''. 1628 1629 1630 \subsection{Routine Nesting} 1631 1632 While \CFA does not provide object programming by putting routines into structures, it does rely heavily on locally nested routines to redefine operations at or close to a call site. 1633 For example, the C quick-sort is wrapped into the following polymorphic \CFA routine: 1634 \begin{cfa} 1635 forall( otype T | { int ?<?( T, T ); } ) 1636 void qsort( const T * arr, size_t dimension ); 1637 \end{cfa} 1638 which can be used to sort in ascending and descending order by locally redefining the less-than operator into greater-than. 1639 \begin{cfa} 1640 const unsigned int size = 5; 1641 int ia[size]; 1642 ... §\C{// assign values to array ia}§ 1643 qsort( ia, size ); §\C{// sort ascending order using builtin ?<?}§ 1644 { 1645 ®int ?<?( int x, int y ) { return x > y; }® §\C{// nested routine}§ 1646 qsort( ia, size ); §\C{// sort descending order by local redefinition}§ 1647 } 1648 \end{cfa} 1649 1650 Nested routines are not first-class, meaning a nested routine cannot be returned if it has references to variables in its enclosing blocks; 1651 the only exception is references to the external block of the translation unit, as these variables persist for the duration of the program. 1652 The following program in undefined in \CFA (and Indexc{gcc}) 1653 \begin{cfa} 1654 [* [int]( int )] foo() { §\C{// int (*foo())( int )}§ 1655 int ®i® = 7; 1656 int bar( int p ) { 1657 ®i® += 1; §\C{// dependent on local variable}§ 1658 sout | ®i® | endl; 1659 } 1660 return bar; §\C{// undefined because of local dependence}§ 1661 } 1662 int main() { 1663 * [int]( int ) fp = foo(); §\C{// int (*fp)( int )}§ 1664 sout | fp( 3 ) | endl; 1665 } 1666 \end{cfa} 1667 because 1668 1669 Currently, there are no \Index{lambda} expressions, \ie unnamed routines because routine names are very important to properly select the correct routine. 1670 1671 1672 \section{Tuples} 1673 1674 In C and \CFA, lists of elements appear in several contexts, such as the parameter list for a routine call. 1675 (More contexts are added shortly.) 1676 A list of such elements is called a \newterm{lexical list}. 1677 The general syntax of a lexical list is: 1678 \begin{cfa} 1679 [ §\emph{exprlist}§ ] 1680 \end{cfa} 1681 where ©$\emph{exprlist}$© is a list of one or more expressions separated by commas. 1682 The brackets, ©[]©, allow differentiating between lexical lists and expressions containing the C comma operator. 1683 The following are examples of lexical lists: 1684 \begin{cfa} 1685 [ x, y, z ] 1686 [ 2 ] 1687 [ v+w, x*y, 3.14159, f() ] 1688 \end{cfa} 1689 Tuples are permitted to contain sub-tuples (\ie nesting), such as ©[ [ 14, 21 ], 9 ]©, which is a 2-element tuple whose first element is itself a tuple. 1690 Note, a tuple is not a record (structure); 1691 a record denotes a single value with substructure, whereas a tuple is multiple values with no substructure (see flattening coercion in Section 12.1). 1692 In essence, tuples are largely a compile time phenomenon, having little or no runtime presence. 1693 1694 Tuples can be organized into compile-time tuple variables; 1695 these variables are of \newterm{tuple type}. 1696 Tuple variables and types can be used anywhere lists of conventional variables and types can be used. 1697 The general syntax of a tuple type is: 1698 \begin{cfa} 1699 [ §\emph{typelist}§ ] 1700 \end{cfa} 1701 where ©$\emph{typelist}$© is a list of one or more legal \CFA or C type specifications separated by commas, which may include other tuple type specifications. 1702 Examples of tuple types include: 1703 \begin{cfa} 1704 [ unsigned int, char ] 1705 [ double, double, double ] 1706 [ * int, int * ] §\C{// mix of CFA and ANSI}§ 1707 [ * [ 5 ] int, * * char, * [ [ int, int ] ] (int, int) ] 1708 \end{cfa} 1709 Like tuples, tuple types may be nested, such as ©[ [ int, int ], int ]©, which is a 2-element tuple type whose first element is itself a tuple type. 1710 1711 Examples of declarations using tuple types are: 1712 \begin{cfa} 1713 [ int, int ] x; §\C{// 2 element tuple, each element of type int}§ 1714 * [ char, char ] y; §\C{// pointer to a 2 element tuple}§ 1715 [ [ int, int ] ] z ([ int, int ]); 1716 \end{cfa} 1717 The last example declares an external routine that expects a 2 element tuple as an input parameter and returns a 2 element tuple as its result. 1718 1719 As mentioned, tuples can appear in contexts requiring a list of value, such as an argument list of a routine call. 1720 In unambiguous situations, the tuple brackets may be omitted, \eg a tuple that appears as an argument may have its 1721 square brackets omitted for convenience; therefore, the following routine invocations are equivalent: 1722 \begin{cfa} 1723 f( [ 1, x+2, fred() ] ); 1724 f( 1, x+2, fred() ); 1725 \end{cfa} 1726 Also, a tuple or a tuple variable may be used to supply all or part of an argument list for a routine expecting multiple input parameters or for a routine expecting a tuple as an input parameter. 1727 For example, the following are all legal: 1728 \begin{cfa} 1729 [ int, int ] w1; 1730 [ int, int, int ] w2; 1731 [ void ] f (int, int, int); /* three input parameters of type int */ 1732 [ void ] g ([ int, int, int ]); /* 3 element tuple as input */ 1733 f( [ 1, 2, 3 ] ); 1734 f( w1, 3 ); 1735 f( 1, w1 ); 1736 f( w2 ); 1737 g( [ 1, 2, 3 ] ); 1738 g( w1, 3 ); 1739 g( 1, w1 ); 1740 g( w2 ); 1741 \end{cfa} 1742 Note, in all cases 3 arguments are supplied even though the syntax may appear to supply less than 3. As mentioned, a 1743 tuple does not have structure like a record; a tuple is simply converted into a list of components. 1744 \begin{rationale} 1745 The present implementation of \CFA does not support nested routine calls when the inner routine returns multiple values; \ie a statement such as ©g( f() )© is not supported. 1746 Using a temporary variable to store the results of the inner routine and then passing this variable to the outer routine works, however. 1747 \end{rationale} 1748 1749 A tuple can contain a C comma expression, provided the expression containing the comma operator is enclosed in parentheses. 1750 For instance, the following tuples are equivalent: 1751 \begin{cfa} 1752 [ 1, 3, 5 ] 1753 [ 1, (2, 3), 5 ] 1754 \end{cfa} 1755 The second element of the second tuple is the expression (2, 3), which yields the result 3. 1756 This requirement is the same as for comma expressions in argument lists. 1757 1758 Type qualifiers, \ie const and volatile, may modify a tuple type. 1759 The meaning is the same as for a type qualifier modifying an aggregate type [Int99, x 6.5.2.3(7),x 6.7.3(11)], \ie the qualifier is distributed across all of the types in the tuple, \eg: 1760 \begin{cfa} 1761 const volatile [ int, float, const int ] x; 1762 \end{cfa} 1763 is equivalent to: 1764 \begin{cfa} 1765 [ const volatile int, const volatile float, const volatile int ] x; 1766 \end{cfa} 1767 Declaration qualifiers can only appear at the start of a \CFA tuple declaration4, \eg: 1768 \begin{cfa} 1769 extern [ int, int ] w1; 1770 static [ int, int, int ] w2; 1771 \end{cfa} 1772 \begin{rationale} 1773 Unfortunately, C's syntax for subscripts precluded treating them as tuples. 1774 The C subscript list has the form ©[i][j]...© and not ©[i, j, ...]©. 1775 Therefore, there is no syntactic way for a routine returning multiple values to specify the different subscript values, \eg ©f[g()]© always means a single subscript value because there is only one set of brackets. 1776 Fixing this requires a major change to C because the syntactic form ©M[i, j, k]© already has a particular meaning: ©i, j, k© is a comma expression. 1777 \end{rationale} 1778 1779 1780 \subsection{Tuple Coercions} 1781 1782 There are four coercions that can be performed on tuples and tuple variables: closing, opening, flattening and structuring. 1783 In addition, the coercion of dereferencing can be performed on a tuple variable to yield its value(s), as for other variables. 1784 A \newterm{closing coercion} takes a set of values and converts it into a tuple value, which is a contiguous set of values, as in: 1785 \begin{cfa} 1786 [ int, int, int, int ] w; 1787 w = [ 1, 2, 3, 4 ]; 1788 \end{cfa} 1789 First the right-hand tuple is closed into a tuple value and then the tuple value is assigned. 1790 1791 An \newterm{opening coercion} is the opposite of closing; a tuple value is converted into a tuple of values, as in: 1792 \begin{cfa} 1793 [ a, b, c, d ] = w 1794 \end{cfa} 1795 ©w© is implicitly opened to yield a tuple of four values, which are then assigned individually. 1796 1797 A \newterm{flattening coercion} coerces a nested tuple, \ie a tuple with one or more components, which are themselves tuples, into a flattened tuple, which is a tuple whose components are not tuples, as in: 1798 \begin{cfa} 1799 [ a, b, c, d ] = [ 1, [ 2, 3 ], 4 ]; 1800 \end{cfa} 1801 First the right-hand tuple is flattened and then the values are assigned individually. 1802 Flattening is also performed on tuple types. 1803 For example, the type ©[ int, [ int, int ], int ]© can be coerced, using flattening, into the type ©[ int, int, int, int ]©. 1804 1805 A \newterm{structuring coercion} is the opposite of flattening; 1806 a tuple is structured into a more complex nested tuple. 1807 For example, structuring the tuple ©[ 1, 2, 3, 4 ]© into the tuple ©[ 1, [ 2, 3 ], 4 ]© or the tuple type ©[ int, int, int, int ]© into the tuple type ©[ int, [ int, int ], int ]©. 1808 In the following example, the last assignment illustrates all the tuple coercions: 1809 \begin{cfa} 1810 [ int, int, int, int ] w = [ 1, 2, 3, 4 ]; 1811 int x = 5; 1812 [ x, w ] = [ w, x ]; §\C{// all four tuple coercions}§ 1813 \end{cfa} 1814 Starting on the right-hand tuple in the last assignment statement, w is opened, producing a tuple of four values; 1815 therefore, the right-hand tuple is now the tuple ©[ [ 1, 2, 3, 4 ], 5 ]©. 1816 This tuple is then flattened, yielding ©[ 1, 2, 3, 4, 5 ]©, which is structured into ©[ 1, [ 2, 3, 4, 5 ] ]© to match the tuple type of the left-hand side. 1817 The tuple ©[ 2, 3, 4, 5 ]© is then closed to create a tuple value. 1818 Finally, ©x© is assigned ©1© and ©w© is assigned the tuple value using multiple assignment (see Section 14). 1819 \begin{rationale} 1820 A possible additional language extension is to use the structuring coercion for tuples to initialize a complex record with a tuple. 1821 \end{rationale} 1822 1823 1824 \section{Mass Assignment} 1825 1826 \CFA permits assignment to several variables at once using mass assignment~\cite{CLU}. 1827 Mass assignment has the following form: 1828 \begin{cfa} 1829 [ §\emph{lvalue}§, ... , §\emph{lvalue}§ ] = §\emph{expr}§; 1830 \end{cfa} 1831 \index{lvalue} 1832 The left-hand side is a tuple of \emph{lvalues}, which is a list of expressions each yielding an address, \ie any data object that can appear on the left-hand side of a conventional assignment statement. 1833 ©$\emph{expr}$© is any standard arithmetic expression. 1834 Clearly, the types of the entities being assigned must be type compatible with the value of the expression. 1835 1836 Mass assignment has parallel semantics, \eg the statement: 1837 \begin{cfa} 1838 [ x, y, z ] = 1.5; 1839 \end{cfa} 1840 is equivalent to: 1841 \begin{cfa} 1842 x = 1.5; y = 1.5; z = 1.5; 1843 \end{cfa} 1844 This semantics is not the same as the following in C: 1845 \begin{cfa} 1846 x = y = z = 1.5; 1847 \end{cfa} 1848 as conversions between intermediate assignments may lose information. 1849 A more complex example is: 1850 \begin{cfa} 1851 [ i, y[i], z ] = a + b; 1852 \end{cfa} 1853 which is equivalent to: 1854 \begin{cfa} 1855 t = a + b; 1856 a1 = &i; a2 = &y[i]; a3 = &z; 1857 *a1 = t; *a2 = t; *a3 = t; 1858 \end{cfa} 1859 The temporary ©t© is necessary to store the value of the expression to eliminate conversion issues. 1860 The temporaries for the addresses are needed so that locations on the left-hand side do not change as the values are assigned. 1861 In this case, ©y[i]© uses the previous value of ©i© and not the new value set at the beginning of the mass assignment. 1862 1863 1864 \section{Multiple Assignment} 1865 1866 \CFA also supports the assignment of several values at once, known as multiple assignment~\cite{CLU,Galletly96}. 1867 Multiple assignment has the following form: 1868 \begin{cfa} 1869 [ §\emph{lvalue}§, ... , §\emph{lvalue}§ ] = [ §\emph{expr}§, ... , §\emph{expr}§ ]; 1870 \end{cfa} 1871 \index{lvalue} 1872 The left-hand side is a tuple of \emph{lvalues}, and the right-hand side is a tuple of \emph{expr}s. 1873 Each \emph{expr} appearing on the right-hand side of a multiple assignment statement is assigned to the corresponding \emph{lvalues} on the left-hand side of the statement using parallel semantics for each assignment. 1874 An example of multiple assignment is: 1875 \begin{cfa} 1876 [ x, y, z ] = [ 1, 2, 3 ]; 1877 \end{cfa} 1878 Here, the values ©1©, ©2© and ©3© are assigned, respectively, to the variables ©x©, ©y© and ©z©. 1879 A more complex example is: 1880 \begin{cfa} 1881 [ i, y[ i ], z ] = [ 1, i, a + b ]; 1882 \end{cfa} 1883 Here, the values ©1©, ©i© and ©a + b© are assigned to the variables ©i©, ©y[i]© and ©z©, respectively. 1884 Note, the parallel semantics of 1885 multiple assignment ensures: 1886 \begin{cfa} 1887 [ x, y ] = [ y, x ]; 1888 \end{cfa} 1889 correctly interchanges (swaps) the values stored in ©x© and ©y©. 1890 The following cases are errors: 1891 \begin{cfa} 1892 [ a, b, c ] = [ 1, 2, 3, 4 ]; 1893 [ a, b, c ] = [ 1, 2 ]; 1894 \end{cfa} 1895 because the number of entities in the left-hand tuple is unequal with the right-hand tuple. 1896 1897 As for all tuple contexts in C, side effects should not be used because C does not define an ordering for the evaluation of the elements of a tuple; 1898 both these examples produce indeterminate results: 1899 \begin{cfa} 1900 f( x++, x++ ); §\C{// C routine call with side effects in arguments}§ 1901 [ v1, v2 ] = [ x++, x++ ]; §\C{// side effects in righthand side of multiple assignment}§ 1902 \end{cfa} 1903 1904 1905 \section{Cascade Assignment} 1906 1907 As in C, \CFA mass and multiple assignments can be cascaded, producing cascade assignment. 1908 Cascade assignment has the following form: 1909 \begin{cfa} 1910 §\emph{tuple}§ = §\emph{tuple}§ = ... = §\emph{tuple}§; 1911 \end{cfa} 1912 and it has the same parallel semantics as for mass and multiple assignment. 1913 Some examples of cascade assignment are: 1914 \begin{cfa} 1915 x1 = y1 = x2 = y2 = 0; 1916 [ x1, y1 ] = [ x2, y2 ] = [ x3, y3 ]; 1917 [ x1, y1 ] = [ x2, y2 ] = 0; 1918 [ x1, y1 ] = z = 0; 1919 \end{cfa} 1920 As in C, the rightmost assignment is performed first, \ie assignment parses right to left. 1921 1922 1923 \section{Field Tuples} 1924 1925 Tuples may be used to select multiple fields of a record by field name. 1926 Its general form is: 1927 \begin{cfa} 1928 §\emph{expr}§ . [ §\emph{fieldlist}§ ] 1929 §\emph{expr}§ -> [ §\emph{fieldlist}§ ] 1930 \end{cfa} 1931 \emph{expr} is any expression yielding a value of type record, \eg ©struct©, ©union©. 1932 Each element of \emph{ fieldlist} is an element of the record specified by \emph{expr}. 1933 A record-field tuple may be used anywhere a tuple can be used. An example of the use of a record-field tuple is 1934 the following: 1935 \begin{cfa} 1936 struct s { 1937 int f1, f2; 1938 char f3; 1939 double f4; 1940 } v; 1941 v.[ f3, f1, f2 ] = ['x', 11, 17 ]; §\C{// equivalent to v.f3 = 'x', v.f1 = 11, v.f2 = 17}§ 1942 f( v.[ f3, f1, f2 ] ); §\C{// equivalent to f( v.f3, v.f1, v.f2 )}§ 1943 \end{cfa} 1944 Note, the fields appearing in a record-field tuple may be specified in any order; 1945 also, it is unnecessary to specify all the fields of a struct in a multiple record-field tuple. 1946 1947 If a field of a ©struct© is itself another ©struct©, multiple fields of this subrecord can be specified using a nested record-field tuple, as in the following example: 1948 \begin{cfa} 1949 struct inner { 1950 int f2, f3; 1951 }; 1952 struct outer { 1953 int f1; 1954 struct inner i; 1955 double f4; 1956 } o; 1957 1958 o.[ f1, i.[ f2, f3 ], f4 ] = [ 11, 12, 13, 3.14159 ]; 1959 \end{cfa} 491 1960 492 1961 … … 780 2249 still works. 781 2250 Nevertheless, reversing the default action would have a non-trivial effect on case actions that compound, such as the above example of processing shell arguments. 782 Therefore, to preserve backwards compatibility, it is necessary to introduce a new kind of ©switch© statement, called ©choose©, with no implicit fall-through semantics and an explicit fall-through if the last statement of a case-clause ends with the new keyword ©fallthrough©/©fallthru©, \eg:2251 Therefore, to preserve backwards compatibility, it is necessary to introduce a new kind of ©switch© statement, called ©choose©, with no implicit fall-through semantics and an explicit fall-through if the last statement of a case-clause ends with the new keyword ©fallthrough©/©fallthru©, e.g.: 783 2252 \begin{cfa} 784 2253 ®choose® ( i ) { … … 928 2397 929 2398 930 \subsection{Exception Hierarchy}931 932 An exception type can be derived from another exception type, just like deriving a subclass from a class, providing a kind of polymorphism among exception types.933 The exception-type hierarchy that is created is used to organize exception types, similar to a class hierarchy in object-oriented languages, \eg:934 \begin{center}935 \input{EHMHierarchy}936 \end{center}937 A programmer can then choose to handle an exception at different degrees of specificity along the hierarchy;938 derived exception-types support a more flexible programming style.939 For example, higher-level code should catch general exceptions to reduce coupling to the specific implementation at the lower levels;940 unnecessary coupling may force changes in higher-level code when low-level code changes.941 A consequence of derived exception-types is that multiple exceptions may match, \eg:942 \begin{cfa}943 catch( Arithmetic )944 \end{cfa}945 matches all three derived exception-types: ©DivideByZero©, ©Overflow©, and ©Underflow©.946 Because the propagation mechanisms perform a simple linear search of the handler clause for a guarded block, and selects the first matching handler, the order of catch clauses in the handler clause becomes important, \eg:947 \begin{cfa}948 try {949 ...950 } catch( Overflow ) { // must appear first951 // handle overflow952 } catch( Arithmetic )953 // handle other arithmetic issues954 }955 \end{cfa}956 \newterm{Multiple derivation} among exception is not supported.957 958 959 \section{Declarations}960 \label{s:Declarations}961 962 C declaration syntax is notoriously confusing and error prone.963 For example, many C programmers are confused by a declaration as simple as:964 \begin{quote2}965 \begin{tabular}{@{}ll@{}}966 \begin{cfa}967 int * x[5]968 \end{cfa}969 &970 \raisebox{-0.75\totalheight}{\input{Cdecl}}971 \end{tabular}972 \end{quote2}973 Is this an array of 5 pointers to integers or a \Index{pointer} to an array of 5 integers?974 The fact this declaration is unclear to many C programmers means there are \Index{productivity} and \Index{safety} issues even for basic programs.975 Another example of confusion results from the fact that a routine name and its parameters are embedded within the return type, mimicking the way the return value is used at the routine's call site.976 For example, a routine returning a \Index{pointer} to an array of integers is defined and used in the following way:977 \begin{cfa}978 int ®(*®f®())[®5®]® {...}; §\C{definition}§979 ... ®(*®f®())[®3®]® += 1; §\C{usage}§980 \end{cfa}981 Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}).982 While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice.983 984 \CFA provides its own type, variable and routine declarations, using a different syntax.985 The new declarations place qualifiers to the left of the base type, while C declarations place qualifiers to the right of the base type.986 In the following example, \R{red} is the base type and \B{blue} is qualifiers.987 The \CFA declarations move the qualifiers to the left of the base type, \ie move the blue to the left of the red, while the qualifiers have the same meaning but are ordered left to right to specify a variable's type.988 \begin{quote2}989 \begin{tabular}{@{}l@{\hspace{3em}}l@{}}990 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\991 \begin{cfa}992 ß[5] *ß ®int® x1;993 ß* [5]ß ®int® x2;994 ß[* [5] int]ß f®( int p )®;995 \end{cfa}996 &997 \begin{cfa}998 ®int® ß*ß x1 ß[5]ß;999 ®int® ß(*ßx2ß)[5]ß;1000 ßint (*ßf®( int p )®ß)[5]ß;1001 \end{cfa}1002 \end{tabular}1003 \end{quote2}1004 The only exception is \Index{bit field} specification, which always appear to the right of the base type.1005 % Specifically, the character ©*© is used to indicate a pointer, square brackets ©[©\,©]© are used to represent an array or function return value, and parentheses ©()© are used to indicate a routine parameter.1006 However, unlike C, \CFA type declaration tokens are distributed across all variables in the declaration list.1007 For instance, variables ©x© and ©y© of type \Index{pointer} to integer are defined in \CFA as follows:1008 \begin{quote2}1009 \begin{tabular}{@{}l@{\hspace{3em}}l@{}}1010 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\1011 \begin{cfa}1012 ®*® int x, y;1013 \end{cfa}1014 &1015 \begin{cfa}1016 int ®*®x, ®*®y;1017 \end{cfa}1018 \end{tabular}1019 \end{quote2}1020 The downside of this semantics is the need to separate regular and \Index{pointer} declarations:1021 \begin{quote2}1022 \begin{tabular}{@{}l@{\hspace{3em}}l@{}}1023 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\1024 \begin{cfa}1025 ®*® int x;1026 int y;1027 \end{cfa}1028 &1029 \begin{cfa}1030 int ®*®x, y;1031 1032 \end{cfa}1033 \end{tabular}1034 \end{quote2}1035 which is \Index{prescribing} a safety benefit.1036 Other examples are:1037 \begin{quote2}1038 \begin{tabular}{@{}l@{\hspace{3em}}l@{\hspace{2em}}l@{}}1039 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c@{\hspace{2em}}}{\textbf{C}} \\1040 \begin{cfa}1041 [ 5 ] int z;1042 [ 5 ] * char w;1043 * [ 5 ] double v;1044 struct s {1045 int f0:3;1046 * int f1;1047 [ 5 ] * int f2;1048 };1049 \end{cfa}1050 &1051 \begin{cfa}1052 int z[ 5 ];1053 char * w[ 5 ];1054 double (* v)[ 5 ];1055 struct s {1056 int f0:3;1057 int * f1;1058 int * f2[ 5 ]1059 };1060 \end{cfa}1061 &1062 \begin{cfa}1063 // array of 5 integers1064 // array of 5 pointers to char1065 // pointer to array of 5 doubles1066 1067 // common bit field syntax1068 1069 1070 1071 \end{cfa}1072 \end{tabular}1073 \end{quote2}1074 1075 All type qualifiers, \eg ©const©, ©volatile©, etc., are used in the normal way with the new declarations and also appear left to right, \eg:1076 \begin{quote2}1077 \begin{tabular}{@{}l@{\hspace{1em}}l@{\hspace{1em}}l@{}}1078 \multicolumn{1}{c@{\hspace{1em}}}{\textbf{\CFA}} & \multicolumn{1}{c@{\hspace{1em}}}{\textbf{C}} \\1079 \begin{cfa}1080 const * const int x;1081 const * [ 5 ] const int y;1082 \end{cfa}1083 &1084 \begin{cfa}1085 int const * const x;1086 const int (* const y)[ 5 ]1087 \end{cfa}1088 &1089 \begin{cfa}1090 // const pointer to const integer1091 // const pointer to array of 5 const integers1092 \end{cfa}1093 \end{tabular}1094 \end{quote2}1095 All declaration qualifiers, \eg ©extern©, ©static©, etc., are used in the normal way with the new declarations but can only appear at the start of a \CFA routine declaration,\footnote{\label{StorageClassSpecifier}1096 The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature.~\cite[\S~6.11.5(1)]{C11}} \eg:1097 \begin{quote2}1098 \begin{tabular}{@{}l@{\hspace{3em}}l@{\hspace{2em}}l@{}}1099 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c@{\hspace{2em}}}{\textbf{C}} \\1100 \begin{cfa}1101 extern [ 5 ] int x;1102 static * const int y;1103 \end{cfa}1104 &1105 \begin{cfa}1106 int extern x[ 5 ];1107 const int static * y;1108 \end{cfa}1109 &1110 \begin{cfa}1111 // externally visible array of 5 integers1112 // internally visible pointer to constant int1113 \end{cfa}1114 \end{tabular}1115 \end{quote2}1116 1117 The new declaration syntax can be used in other contexts where types are required, \eg casts and the pseudo-routine ©sizeof©:1118 \begin{quote2}1119 \begin{tabular}{@{}l@{\hspace{3em}}l@{}}1120 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\1121 \begin{cfa}1122 y = (®* int®)x;1123 i = sizeof(®[ 5 ] * int®);1124 \end{cfa}1125 &1126 \begin{cfa}1127 y = (®int *®)x;1128 i = sizeof(®int * [ 5 ]®);1129 \end{cfa}1130 \end{tabular}1131 \end{quote2}1132 1133 Finally, new \CFA declarations may appear together with C declarations in the same program block, but cannot be mixed within a specific declaration.1134 Therefore, a programmer has the option of either continuing to use traditional C declarations or take advantage of the new style.1135 Clearly, both styles need to be supported for some time due to existing C-style header-files, particularly for UNIX systems.1136 1137 1138 \section{Pointer/Reference}1139 1140 C provides a \newterm{pointer type};1141 \CFA adds a \newterm{reference type}.1142 These types may be derived from an object or routine type, called the \newterm{referenced type}.1143 Objects of these types contain an \newterm{address}, which is normally a location in memory, but may also address memory-mapped registers in hardware devices.1144 An integer constant expression with the value 0, or such an expression cast to type ©void *©, is called a \newterm{null-pointer constant}.\footnote{1145 One way to conceptualize the null pointer is that no variable is placed at this address, so the null-pointer address can be used to denote an uninitialized pointer/reference object;1146 \ie the null pointer is guaranteed to compare unequal to a pointer to any object or routine.}1147 An address is \newterm{sound}, if it points to a valid memory location in scope, \ie within the program's execution-environment and has not been freed.1148 Dereferencing an \newterm{unsound} address, including the null pointer, is \Index{undefined}, often resulting in a \Index{memory fault}.1149 1150 A program \newterm{object} is a region of data storage in the execution environment, the contents of which can represent values.1151 In most cases, objects are located in memory at an address, and the variable name for an object is an implicit address to the object generated by the compiler and automatically dereferenced, as in:1152 \begin{quote2}1153 \begin{tabular}{@{}ll@{\hspace{2em}}l@{}}1154 \begin{cfa}1155 int x;1156 x = 3;1157 int y;1158 y = x;1159 \end{cfa}1160 &1161 \raisebox{-0.45\totalheight}{\input{pointer1}}1162 &1163 \begin{cfa}1164 int * ®const® x = (int *)1001165 *x = 3; // implicit dereference1166 int * ®const® y = (int *)104;1167 *y = *x; // implicit dereference1168 \end{cfa}1169 \end{tabular}1170 \end{quote2}1171 where the right example is how the compiler logically interprets the variables in the left example.1172 Since a variable name only points to one address during its lifetime, it is an \Index{immutable} \Index{pointer};1173 hence, the implicit type of pointer variables ©x© and ©y© are constant pointers in the compiler interpretation.1174 In general, variable addresses are stored in instructions instead of loaded from memory, and hence may not occupy storage.1175 These approaches are contrasted in the following:1176 \begin{quote2}1177 \begin{tabular}{@{}l|l@{}}1178 \multicolumn{1}{c|}{explicit variable address} & \multicolumn{1}{c}{implicit variable address} \\1179 \hline1180 \begin{cfa}1181 lda r1,100 // load address of x1182 ld r2,(r1) // load value of x1183 lda r3,104 // load address of y1184 st r2,(r3) // store x into y1185 \end{cfa}1186 &1187 \begin{cfa}1188 1189 ld r2,(100) // load value of x1190 1191 st r2,(104) // store x into y1192 \end{cfa}1193 \end{tabular}1194 \end{quote2}1195 Finally, the immutable nature of a variable's address and the fact that there is no storage for the variable pointer means pointer assignment\index{pointer!assignment}\index{assignment!pointer} is impossible.1196 Therefore, the expression ©x = y© has only one meaning, ©*x = *y©, \ie manipulate values, which is why explicitly writing the dereferences is unnecessary even though it occurs implicitly as part of \Index{instruction decoding}.1197 1198 A \Index{pointer}/\Index{reference} object is a generalization of an object variable-name, \ie a mutable address that can point to more than one memory location during its lifetime.1199 (Similarly, an integer variable can contain multiple integer literals during its lifetime versus an integer constant representing a single literal during its lifetime, and like a variable name, may not occupy storage if the literal is embedded directly into instructions.)1200 Hence, a pointer occupies memory to store its current address, and the pointer's value is loaded by dereferencing, \eg:1201 \begin{quote2}1202 \begin{tabular}{@{}l@{\hspace{2em}}l@{}}1203 \begin{cfa}1204 int x, y, ®*® p1, ®*® p2, ®**® p3;1205 p1 = ®&®x; // p1 points to x1206 p2 = p1; // p2 points to x1207 p1 = ®&®y; // p1 points to y1208 p3 = &p2; // p3 points to p21209 \end{cfa}1210 &1211 \raisebox{-0.5\totalheight}{\input{pointer2.pstex_t}}1212 \end{tabular}1213 \end{quote2}1214 1215 Notice, an address has a \Index{duality}\index{address!duality}: a location in memory or the value at that location.1216 In many cases, a compiler might be able to infer the best meaning for these two cases.1217 For example, \Index*{Algol68}~\cite{Algol68} infers pointer dereferencing to select the best meaning for each pointer usage1218 \begin{cfa}1219 p2 = p1 + x; §\C{// compiler infers *p2 = *p1 + x;}§1220 \end{cfa}1221 Algol68 infers the following dereferencing ©*p2 = *p1 + x©, because adding the arbitrary integer value in ©x© to the address of ©p1© and storing the resulting address into ©p2© is an unlikely operation.1222 Unfortunately, automatic dereferencing does not work in all cases, and so some mechanism is necessary to fix incorrect choices.1223 1224 Rather than inferring dereference, most programming languages pick one implicit dereferencing semantics, and the programmer explicitly indicates the other to resolve address-duality.1225 In C, objects of pointer type always manipulate the pointer object's address:1226 \begin{cfa}1227 p1 = p2; §\C{// p1 = p2\ \ rather than\ \ *p1 = *p2}§1228 p2 = p1 + x; §\C{// p2 = p1 + x\ \ rather than\ \ *p2 = *p1 + x}§1229 \end{cfa}1230 even though the assignment to ©p2© is likely incorrect, and the programmer probably meant:1231 \begin{cfa}1232 p1 = p2; §\C{// pointer address assignment}§1233 ®*®p2 = ®*®p1 + x; §\C{// pointed-to value assignment / operation}§1234 \end{cfa}1235 The C semantics work well for situations where manipulation of addresses is the primary meaning and data is rarely accessed, such as storage management (©malloc©/©free©).1236 1237 However, in most other situations, the pointed-to value is requested more often than the pointer address.1238 \begin{cfa}1239 *p2 = ((*p1 + *p2) * (**p3 - *p1)) / (**p3 - 15);1240 \end{cfa}1241 In this case, it is tedious to explicitly write the dereferencing, and error prone when pointer arithmetic is allowed.1242 It is better to have the compiler generate the dereferencing and have no implicit pointer arithmetic:1243 \begin{cfa}1244 p2 = ((p1 + p2) * (p3 - p1)) / (p3 - 15);1245 \end{cfa}1246 1247 To support this common case, a reference type is introduced in \CFA, denoted by ©&©, which is the opposite dereference semantics to a pointer type, making the value at the pointed-to location the implicit semantics for dereferencing (similar but not the same as \CC \Index{reference type}s).1248 \begin{cfa}1249 int x, y, ®&® r1, ®&® r2, ®&&® r3;1250 ®&®r1 = &x; §\C{// r1 points to x}§1251 ®&®r2 = &r1; §\C{// r2 points to x}§1252 ®&®r1 = &y; §\C{// r1 points to y}§1253 ®&&®r3 = ®&®&r2; §\C{// r3 points to r2}§1254 r2 = ((r1 + r2) * (r3 - r1)) / (r3 - 15); §\C{// implicit dereferencing}§1255 \end{cfa}1256 Except for auto-dereferencing by the compiler, this reference example is the same as the previous pointer example.1257 Hence, a reference behaves like the variable name for the current variable it is pointing-to.1258 One way to conceptualize a reference is via a rewrite rule, where the compiler inserts a dereference operator before the reference variable for each reference qualifier in a declaration, so the previous example becomes:1259 \begin{cfa}1260 ®*®r2 = ((®*®r1 + ®*®r2) ®*® (®**®r3 - ®*®r1)) / (®**®r3 - 15);1261 \end{cfa}1262 When a reference operation appears beside a dereference operation, \eg ©&*©, they cancel out.1263 However, in C, the cancellation always yields a value (\Index{rvalue}).\footnote{1264 The unary ©&© operator yields the address of its operand.1265 If the operand has type ``type'', the result has type ``pointer to type''.1266 If the operand is the result of a unary ©*© operator, neither that operator nor the ©&© operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue.~\cite[\S~6.5.3.2--3]{C11}}1267 For a \CFA reference type, the cancellation on the left-hand side of assignment leaves the reference as an address (\Index{lvalue}):1268 \begin{cfa}1269 (&®*®)r1 = &x; §\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}§1270 \end{cfa}1271 Similarly, the address of a reference can be obtained for assignment or computation (\Index{rvalue}):1272 \begin{cfa}1273 (&(&®*®)®*®)r3 = &(&®*®)r2; §\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}§1274 \end{cfa}1275 Cancellation\index{cancellation!pointer/reference}\index{pointer!cancellation} works to arbitrary depth.1276 1277 Fundamentally, pointer and reference objects are functionally interchangeable because both contain addresses.1278 \begin{cfa}1279 int x, *p1 = &x, **p2 = &p1, ***p3 = &p2,1280 &r1 = x, &&r2 = r1, &&&r3 = r2;1281 ***p3 = 3; §\C{// change x}§1282 r3 = 3; §\C{// change x, ***r3}§1283 **p3 = ...; §\C{// change p1}§1284 &r3 = ...; §\C{// change r1, (\&*)**r3, 1 cancellation}§1285 *p3 = ...; §\C{// change p2}§1286 &&r3 = ...; §\C{// change r2, (\&(\&*)*)*r3, 2 cancellations}§1287 &&&r3 = p3; §\C{// change r3 to p3, (\&(\&(\&*)*)*)r3, 3 cancellations}§1288 \end{cfa}1289 Furthermore, both types are equally performant, as the same amount of dereferencing occurs for both types.1290 Therefore, the choice between them is based solely on whether the address is dereferenced frequently or infrequently, which dictates the amount of implicit dereferencing aid from the compiler.1291 1292 As for a pointer type, a reference type may have qualifiers:1293 \begin{cfa}1294 const int cx = 5; §\C{// cannot change cx;}§1295 const int & cr = cx; §\C{// cannot change what cr points to}§1296 ®&®cr = &cx; §\C{// can change cr}§1297 cr = 7; §\C{// error, cannot change cx}§1298 int & const rc = x; §\C{// must be initialized}§1299 ®&®rc = &x; §\C{// error, cannot change rc}§1300 const int & const crc = cx; §\C{// must be initialized}§1301 crc = 7; §\C{// error, cannot change cx}§1302 ®&®crc = &cx; §\C{// error, cannot change crc}§1303 \end{cfa}1304 Hence, for type ©& const©, there is no pointer assignment, so ©&rc = &x© is disallowed, and \emph{the address value cannot be the null pointer unless an arbitrary pointer is coerced\index{coercion} into the reference}:1305 \begin{cfa}1306 int & const cr = *0; §\C{// where 0 is the int * zero}§1307 \end{cfa}1308 Note, constant reference-types do not prevent \Index{addressing errors} because of explicit storage-management:1309 \begin{cfa}1310 int & const cr = *malloc();1311 cr = 5;1312 free( &cr );1313 cr = 7; §\C{// unsound pointer dereference}§1314 \end{cfa}1315 1316 The position of the ©const© qualifier \emph{after} the pointer/reference qualifier causes confuse for C programmers.1317 The ©const© qualifier cannot be moved before the pointer/reference qualifier for C style-declarations;1318 \CFA-style declarations (see \VRef{s:Declarations}) attempt to address this issue:1319 \begin{quote2}1320 \begin{tabular}{@{}l@{\hspace{3em}}l@{}}1321 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\1322 \begin{cfa}1323 ®const® * ®const® * const int ccp;1324 ®const® & ®const® & const int ccr;1325 \end{cfa}1326 &1327 \begin{cfa}1328 const int * ®const® * ®const® ccp;1329 1330 \end{cfa}1331 \end{tabular}1332 \end{quote2}1333 where the \CFA declaration is read left-to-right.1334 1335 Finally, like pointers, references are usable and composable with other type operators and generators.1336 \begin{cfa}1337 int w, x, y, z, & ar[3] = { x, y, z }; §\C{// initialize array of references}§1338 &ar[1] = &w; §\C{// change reference array element}§1339 typeof( ar[1] ) p; §\C{// (gcc) is int, i.e., the type of referenced object}§1340 typeof( &ar[1] ) q; §\C{// (gcc) is int \&, i.e., the type of reference}§1341 sizeof( ar[1] ) == sizeof( int ); §\C{// is true, i.e., the size of referenced object}§1342 sizeof( &ar[1] ) == sizeof( int *) §\C{// is true, i.e., the size of a reference}§1343 \end{cfa}1344 1345 In contrast to \CFA reference types, \Index*[C++]{\CC{}}'s reference types are all ©const© references, preventing changes to the reference address, so only value assignment is possible, which eliminates half of the \Index{address duality}.1346 Also, \CC does not allow \Index{array}s\index{array!reference} of reference\footnote{1347 The reason for disallowing arrays of reference is unknown, but possibly comes from references being ethereal (like a textual macro), and hence, replaceable by the referant object.}1348 \Index*{Java}'s reference types to objects (all Java objects are on the heap) are like C pointers, which always manipulate the address, and there is no (bit-wise) object assignment, so objects are explicitly cloned by shallow or deep copying, which eliminates half of the address duality.1349 1350 1351 \subsection{Initialization}1352 1353 \Index{Initialization} is different than \Index{assignment} because initialization occurs on the empty (uninitialized) storage on an object, while assignment occurs on possibly initialized storage of an object.1354 There are three initialization contexts in \CFA: declaration initialization, argument/parameter binding, return/temporary binding.1355 Because the object being initialized has no value, there is only one meaningful semantics with respect to address duality: it must mean address as there is no pointed-to value.1356 In contrast, the left-hand side of assignment has an address that has a duality.1357 Therefore, for pointer/reference initialization, the initializing value must be an address not a value.1358 \begin{cfa}1359 int * p = &x; §\C{// assign address of x}§1360 ®int * p = x;® §\C{// assign value of x}§1361 int & r = x; §\C{// must have address of x}§1362 \end{cfa}1363 Like the previous example with C pointer-arithmetic, it is unlikely assigning the value of ©x© into a pointer is meaningful (again, a warning is usually given).1364 Therefore, for safety, this context requires an address, so it is superfluous to require explicitly taking the address of the initialization object, even though the type is incorrect.1365 Note, this is strictly a convenience and safety feature for a programmer.1366 Hence, \CFA allows ©r© to be assigned ©x© because it infers a reference for ©x©, by implicitly inserting a address-of operator, ©&©, and it is an error to put an ©&© because the types no longer match due to the implicit dereference.1367 Unfortunately, C allows ©p© to be assigned with ©&x© (address) or ©x© (value), but most compilers warn about the latter assignment as being potentially incorrect.1368 Similarly, when a reference type is used for a parameter/return type, the call-site argument does not require a reference operator for the same reason.1369 \begin{cfa}1370 int & f( int & r ); §\C{// reference parameter and return}§1371 z = f( x ) + f( y ); §\C{// reference operator added, temporaries needed for call results}§1372 \end{cfa}1373 Within routine ©f©, it is possible to change the argument by changing the corresponding parameter, and parameter ©r© can be locally reassigned within ©f©.1374 Since operator routine ©?+?© takes its arguments by value, the references returned from ©f© are used to initialize compiler generated temporaries with value semantics that copy from the references.1375 \begin{cfa}1376 int temp1 = f( x ), temp2 = f( y );1377 z = temp1 + temp2;1378 \end{cfa}1379 This \Index{implicit referencing} is crucial for reducing the syntactic burden for programmers when using references;1380 otherwise references have the same syntactic burden as pointers in these contexts.1381 1382 When a pointer/reference parameter has a ©const© value (immutable), it is possible to pass literals and expressions.1383 \begin{cfa}1384 void f( ®const® int & cr );1385 void g( ®const® int * cp );1386 f( 3 ); g( ®&®3 );1387 f( x + y ); g( ®&®(x + y) );1388 \end{cfa}1389 Here, the compiler passes the address to the literal 3 or the temporary for the expression ©x + y©, knowing the argument cannot be changed through the parameter.1390 The ©&© before the constant/expression for the pointer-type parameter (©g©) is a \CFA extension necessary to type match and is a common requirement before a variable in C (\eg ©scanf©).1391 Importantly, ©&3© may not be equal to ©&3©, where the references occur across calls because the temporaries maybe different on each call.1392 1393 \CFA \emph{extends} this semantics to a mutable pointer/reference parameter, and the compiler implicitly creates the necessary temporary (copying the argument), which is subsequently pointed-to by the reference parameter and can be changed.\footnote{1394 If whole program analysis is possible, and shows the parameter is not assigned, \ie it is ©const©, the temporary is unnecessary.}1395 \begin{cfa}1396 void f( int & r );1397 void g( int * p );1398 f( 3 ); g( ®&®3 ); §\C{// compiler implicit generates temporaries}§1399 f( x + y ); g( ®&®(x + y) ); §\C{// compiler implicit generates temporaries}§1400 \end{cfa}1401 Essentially, there is an implicit \Index{rvalue} to \Index{lvalue} conversion in this case.\footnote{1402 This conversion attempts to address the \newterm{const hell} problem, when the innocent addition of a ©const© qualifier causes a cascade of type failures, requiring an unknown number of additional ©const© qualifiers, until it is discovered a ©const© qualifier cannot be added and all the ©const© qualifiers must be removed.}1403 The implicit conversion allows seamless calls to any routine without having to explicitly name/copy the literal/expression to allow the call.1404 1405 %\CFA attempts to handle pointers and references in a uniform, symmetric manner.1406 Finally, C handles \Index{routine object}s in an inconsistent way.1407 A routine object is both a pointer and a reference (\Index{particle and wave}).1408 \begin{cfa}1409 void f( int i );1410 void (*fp)( int ); §\C{// routine pointer}§1411 fp = f; §\C{// reference initialization}§1412 fp = &f; §\C{// pointer initialization}§1413 fp = *f; §\C{// reference initialization}§1414 fp(3); §\C{// reference invocation}§1415 (*fp)(3); §\C{// pointer invocation}§1416 \end{cfa}1417 While C's treatment of routine objects has similarity to inferring a reference type in initialization contexts, the examples are assignment not initialization, and all possible forms of assignment are possible (©f©, ©&f©, ©*f©) without regard for type.1418 Instead, a routine object should be referenced by a ©const© reference:1419 \begin{cfa}1420 ®const® void (®&® fr)( int ) = f; §\C{// routine reference}§1421 fr = ... §\C{// error, cannot change code}§1422 &fr = ...; §\C{// changing routine reference}§1423 fr( 3 ); §\C{// reference call to f}§1424 (*fr)(3); §\C{// error, incorrect type}§1425 \end{cfa}1426 because the value of the routine object is a routine literal, \ie the routine code is normally immutable during execution.\footnote{1427 Dynamic code rewriting is possible but only in special circumstances.}1428 \CFA allows this additional use of references for routine objects in an attempt to give a more consistent meaning for them.1429 1430 1431 \subsection{Address-of Semantics}1432 1433 In C, ©&E© is an rvalue for any expression ©E©.1434 \CFA extends the ©&© (address-of) operator as follows:1435 \begin{itemize}1436 \item1437 if ©R© is an \Index{rvalue} of type ©T &$_1$...&$_r$© where $r \ge 1$ references (©&© symbols) than ©&R© has type ©T ®*®&$_{\color{red}2}$...&$_{\color{red}r}$©, \ie ©T© pointer with $r-1$ references (©&© symbols).1438 1439 \item1440 if ©L© is an \Index{lvalue} of type ©T &$_1$...&$_l$© where $l \ge 0$ references (©&© symbols) then ©&L© has type ©T ®*®&$_{\color{red}1}$...&$_{\color{red}l}$©, \ie ©T© pointer with $l$ references (©&© symbols).1441 \end{itemize}1442 The following example shows the first rule applied to different \Index{rvalue} contexts:1443 \begin{cfa}1444 int x, * px, ** ppx, *** pppx, **** ppppx;1445 int & rx = x, && rrx = rx, &&& rrrx = rrx ;1446 x = rrrx; // rrrx is an lvalue with type int &&& (equivalent to x)1447 px = &rrrx; // starting from rrrx, &rrrx is an rvalue with type int *&&& (&x)1448 ppx = &&rrrx; // starting from &rrrx, &&rrrx is an rvalue with type int **&& (&rx)1449 pppx = &&&rrrx; // starting from &&rrrx, &&&rrrx is an rvalue with type int ***& (&rrx)1450 ppppx = &&&&rrrx; // starting from &&&rrrx, &&&&rrrx is an rvalue with type int **** (&rrrx)1451 \end{cfa}1452 The following example shows the second rule applied to different \Index{lvalue} contexts:1453 \begin{cfa}1454 int x, * px, ** ppx, *** pppx;1455 int & rx = x, && rrx = rx, &&& rrrx = rrx ;1456 rrrx = 2; // rrrx is an lvalue with type int &&& (equivalent to x)1457 &rrrx = px; // starting from rrrx, &rrrx is an rvalue with type int *&&& (rx)1458 &&rrrx = ppx; // starting from &rrrx, &&rrrx is an rvalue with type int **&& (rrx)1459 &&&rrrx = pppx; // starting from &&rrrx, &&&rrrx is an rvalue with type int ***& (rrrx)1460 \end{cfa}1461 1462 1463 \subsection{Conversions}1464 1465 C provides a basic implicit conversion to simplify variable usage:1466 \begin{enumerate}1467 \setcounter{enumi}{-1}1468 \item1469 lvalue to rvalue conversion: ©cv T© converts to ©T©, which allows implicit variable dereferencing.1470 \begin{cfa}1471 int x;1472 x + 1; // lvalue variable (int) converts to rvalue for expression1473 \end{cfa}1474 An rvalue has no type qualifiers (©cv©), so the lvalue qualifiers are dropped.1475 \end{enumerate}1476 \CFA provides three new implicit conversion for reference types to simplify reference usage.1477 \begin{enumerate}1478 \item1479 reference to rvalue conversion: ©cv T &© converts to ©T©, which allows implicit reference dereferencing.1480 \begin{cfa}1481 int x, &r = x, f( int p );1482 x = ®r® + f( ®r® ); // lvalue reference converts to rvalue1483 \end{cfa}1484 An rvalue has no type qualifiers (©cv©), so the reference qualifiers are dropped.1485 1486 \item1487 lvalue to reference conversion: \lstinline[deletekeywords={lvalue}]@lvalue-type cv1 T@ converts to ©cv2 T &©, which allows implicitly converting variables to references.1488 \begin{cfa}1489 int x, &r = ®x®, f( int & p ); // lvalue variable (int) convert to reference (int &)1490 f( ®x® ); // lvalue variable (int) convert to reference (int &)1491 \end{cfa}1492 Conversion can restrict a type, where ©cv1© $\le$ ©cv2©, \eg passing an ©int© to a ©const volatile int &©, which has low cost.1493 Conversion can expand a type, where ©cv1© $>$ ©cv2©, \eg passing a ©const volatile int© to an ©int &©, which has high cost (\Index{warning});1494 furthermore, if ©cv1© has ©const© but not ©cv2©, a temporary variable is created to preserve the immutable lvalue.1495 1496 \item1497 rvalue to reference conversion: ©T© converts to ©cv T &©, which allows binding references to temporaries.1498 \begin{cfa}1499 int x, & f( int & p );1500 f( ®x + 3® ); // rvalue parameter (int) implicitly converts to lvalue temporary reference (int &)1501 ®&f®(...) = &x; // rvalue result (int &) implicitly converts to lvalue temporary reference (int &)1502 \end{cfa}1503 In both case, modifications to the temporary are inaccessible (\Index{warning}).1504 Conversion expands the temporary-type with ©cv©, which is low cost since the temporary is inaccessible.1505 \end{enumerate}1506 1507 1508 \begin{comment}1509 From: Richard Bilson <rcbilson@gmail.com>1510 Date: Wed, 13 Jul 2016 01:58:58 +00001511 Subject: Re: pointers / references1512 To: "Peter A. Buhr" <pabuhr@plg2.cs.uwaterloo.ca>1513 1514 As a general comment I would say that I found the section confusing, as you move back and forth1515 between various real and imagined programming languages. If it were me I would rewrite into two1516 subsections, one that specifies precisely the syntax and semantics of reference variables and1517 another that provides the rationale.1518 1519 I don't see any obvious problems with the syntax or semantics so far as I understand them. It's not1520 obvious that the description you're giving is complete, but I'm sure you'll find the special cases1521 as you do the implementation.1522 1523 My big gripes are mostly that you're not being as precise as you need to be in your terminology, and1524 that you say a few things that aren't actually true even though I generally know what you mean.1525 1526 20 C provides a pointer type; CFA adds a reference type. Both types contain an address, which is normally a1527 21 location in memory.1528 1529 An address is not a location in memory; an address refers to a location in memory. Furthermore it1530 seems weird to me to say that a type "contains" an address; rather, objects of that type do.1531 1532 21 Special addresses are used to denote certain states or access co-processor memory. By1533 22 convention, no variable is placed at address 0, so addresses like 0, 1, 2, 3 are often used to denote no-value1534 23 or other special states.1535 1536 This isn't standard C at all. There has to be one null pointer representation, but it doesn't have1537 to be a literal zero representation and there doesn't have to be more than one such representation.1538 1539 23 Often dereferencing a special state causes a memory fault, so checking is necessary1540 24 during execution.1541 1542 I don't see the connection between the two clauses here. I feel like if a bad pointer will not cause1543 a memory fault then I need to do more checking, not less.1544 1545 24 If the programming language assigns addresses, a program's execution is sound, \ie all1546 25 addresses are to valid memory locations.1547 1548 You haven't said what it means to "assign" an address, but if I use my intuitive understanding of1549 the term I don't see how this can be true unless you're assuming automatic storage management.1550 1551 1 Program variables are implicit pointers to memory locations generated by the compiler and automatically1552 2 dereferenced, as in:1553 1554 There is no reason why a variable needs to have a location in memory, and indeed in a typical1555 program many variables will not. In standard terminology an object identifier refers to data in the1556 execution environment, but not necessarily in memory.1557 1558 13 A pointer/reference is a generalization of a variable name, \ie a mutable address that can point to more1559 14 than one memory location during its lifetime.1560 1561 I feel like you're off the reservation here. In my world there are objects of pointer type, which1562 seem to be what you're describing here, but also pointer values, which can be stored in an object of1563 pointer type but don't necessarily have to be. For example, how would you describe the value denoted1564 by "&main" in a C program? I would call it a (function) pointer, but that doesn't satisfy your1565 definition.1566 1567 16 not occupy storage as the literal is embedded directly into instructions.) Hence, a pointer occupies memory1568 17 to store its current address, and the pointer's value is loaded by dereferencing, \eg:1569 1570 As with my general objection regarding your definition of variables, there is no reason why a1571 pointer variable (object of pointer type) needs to occupy memory.1572 1573 21 p2 = p1 + x; // compiler infers *p2 = *p1 + x;1574 1575 What language are we in now?1576 1577 24 pointer usage. However, in C, the following cases are ambiguous, especially with pointer arithmetic:1578 25 p1 = p2; // p1 = p2 or *p1 = *p21579 1580 This isn't ambiguous. it's defined to be the first option.1581 1582 26 p1 = p1 + 1; // p1 = p1 + 1 or *p1 = *p1 + 11583 1584 Again, this statement is not ambiguous.1585 1586 13 example. Hence, a reference behaves like the variable name for the current variable it is pointing-to. The1587 14 simplest way to understand a reference is to imagine the compiler inserting a dereference operator before1588 15 the reference variable for each reference qualifier in a declaration, \eg:1589 1590 It's hard for me to understand who the audience for this part is. I think a practical programmer is1591 likely to be satisfied with "a reference behaves like the variable name for the current variable it1592 is pointing-to," maybe with some examples. Your "simplest way" doesn't strike me as simpler than1593 that. It feels like you're trying to provide a more precise definition for the semantics of1594 references, but it isn't actually precise enough to be a formal specification. If you want to1595 express the semantics of references using rewrite rules that's a great way to do it, but lay the1596 rules out clearly, and when you're showing an example of rewriting keep your1597 references/pointers/values separate (right now, you use \eg "r3" to mean a reference, a pointer,1598 and a value).1599 1600 24 Cancellation works to arbitrary depth, and pointer and reference values are interchangeable because both1601 25 contain addresses.1602 1603 Except they're not interchangeable, because they have different and incompatible types.1604 1605 40 Interestingly, C++ deals with the address duality by making the pointed-to value the default, and prevent-1606 41 ing changes to the reference address, which eliminates half of the duality. Java deals with the address duality1607 42 by making address assignment the default and requiring field assignment (direct or indirect via methods),1608 43 \ie there is no builtin bit-wise or method-wise assignment, which eliminates half of the duality.1609 1610 I can follow this but I think that's mostly because I already understand what you're trying to1611 say. I don't think I've ever heard the term "method-wise assignment" and I don't see you defining1612 it. Furthermore Java does have value assignment of basic (non-class) types, so your summary here1613 feels incomplete. (If it were me I'd drop this paragraph rather than try to save it.)1614 1615 11 Hence, for type & const, there is no pointer assignment, so &rc = &x is disallowed, and the address value1616 12 cannot be 0 unless an arbitrary pointer is assigned to the reference.1617 1618 Given the pains you've taken to motivate every little bit of the semantics up until now, this last1619 clause ("the address value cannot be 0") comes out of the blue. It seems like you could have1620 perfectly reasonable semantics that allowed the initialization of null references.1621 1622 12 In effect, the compiler is managing the1623 13 addresses for type & const not the programmer, and by a programming discipline of only using references1624 14 with references, address errors can be prevented.1625 1626 Again, is this assuming automatic storage management?1627 1628 18 rary binding. For reference initialization (like pointer), the initializing value must be an address (lvalue) not1629 19 a value (rvalue).1630 1631 This sentence appears to suggest that an address and an lvalue are the same thing.1632 1633 20 int * p = &x; // both &x and x are possible interpretations1634 1635 Are you saying that we should be considering "x" as a possible interpretation of the initializer1636 "&x"? It seems to me that this expression has only one legitimate interpretation in context.1637 1638 21 int & r = x; // x unlikely interpretation, because of auto-dereferencing1639 1640 You mean, we can initialize a reference using an integer value? Surely we would need some sort of1641 cast to induce that interpretation, no?1642 1643 22 Hence, the compiler implicitly inserts a reference operator, &, before the initialization expression.1644 1645 But then the expression would have pointer type, which wouldn't be compatible with the type of r.1646 1647 22 Similarly,1648 23 when a reference is used for a parameter/return type, the call-site argument does not require a reference1649 24 operator.1650 1651 Furthermore, it would not be correct to use a reference operator.1652 1653 45 The implicit conversion allows1654 1 seamless calls to any routine without having to explicitly name/copy the literal/expression to allow the call.1655 2 While C' attempts to handle pointers and references in a uniform, symmetric manner, C handles routine1656 3 variables in an inconsistent way: a routine variable is both a pointer and a reference (particle and wave).1657 1658 After all this talk of how expressions can have both pointer and value interpretations, you're1659 disparaging C because it has expressions that have both pointer and value interpretations?1660 1661 On Sat, Jul 9, 2016 at 4:18 PM Peter A. Buhr <pabuhr@plg.uwaterloo.ca> wrote:1662 > Aaron discovered a few places where "&"s are missing and where there are too many "&", which are1663 > corrected in the attached updated. None of the text has changed, if you have started reading1664 > already.1665 \end{comment}1666 1667 1668 \section{Routine Definition}1669 1670 \CFA also supports a new syntax for routine definition, as well as \Celeven and K\&R routine syntax.1671 The point of the new syntax is to allow returning multiple values from a routine~\cite{Galletly96,CLU}, \eg:1672 \begin{cfa}1673 ®[ int o1, int o2, char o3 ]® f( int i1, char i2, char i3 ) {1674 §\emph{routine body}§1675 }1676 \end{cfa}1677 where routine ©f© has three output (return values) and three input parameters.1678 Existing C syntax cannot be extended with multiple return types because it is impossible to embed a single routine name within multiple return type specifications.1679 1680 In detail, the brackets, ©[]©, enclose the result type, where each return value is named and that name is a local variable of the particular return type.\footnote{1681 \Index*{Michael Tiemann}, with help from \Index*{Doug Lea}, provided named return values in g++, circa 1989.}1682 The value of each local return variable is automatically returned at routine termination.1683 Declaration qualifiers can only appear at the start of a routine definition, \eg:1684 \begin{cfa}1685 ®extern® [ int x ] g( int y ) {§\,§}1686 \end{cfa}1687 Lastly, if there are no output parameters or input parameters, the brackets and/or parentheses must still be specified;1688 in both cases the type is assumed to be void as opposed to old style C defaults of int return type and unknown parameter types, respectively, as in:1689 \begin{cfa}1690 [§\,§] g(); §\C{// no input or output parameters}§1691 [ void ] g( void ); §\C{// no input or output parameters}§1692 \end{cfa}1693 1694 Routine f is called as follows:1695 \begin{cfa}1696 [ i, j, ch ] = f( 3, 'a', ch );1697 \end{cfa}1698 The list of return values from f and the grouping on the left-hand side of the assignment is called a \newterm{return list} and discussed in Section 12.1699 1700 \CFA style declarations cannot be used to declare parameters for K\&R style routine definitions because of the following ambiguity:1701 \begin{cfa}1702 int (*f(x))[ 5 ] int x; {}1703 \end{cfa}1704 The string ``©int (*f(x))[ 5 ]©'' declares a K\&R style routine of type returning a pointer to an array of 5 integers, while the string ``©[ 5 ] int x©'' declares a \CFA style parameter x of type array of 5 integers.1705 Since the strings overlap starting with the open bracket, ©[©, there is an ambiguous interpretation for the string.1706 As well, \CFA-style declarations cannot be used to declare parameters for C-style routine-definitions because of the following ambiguity:1707 \begin{cfa}1708 typedef int foo;1709 int f( int (* foo) ); §\C{// foo is redefined as a parameter name}§1710 \end{cfa}1711 The string ``©int (* foo)©'' declares a C-style named-parameter of type pointer to an integer (the parenthesis are superfluous), while the same string declares a \CFA style unnamed parameter of type routine returning integer with unnamed parameter of type pointer to foo.1712 The redefinition of a type name in a parameter list is the only context in C where the character ©*© can appear to the left of a type name, and \CFA relies on all type qualifier characters appearing to the right of the type name.1713 The inability to use \CFA declarations in these two contexts is probably a blessing because it precludes programmers from arbitrarily switching between declarations forms within a declaration contexts.1714 1715 C-style declarations can be used to declare parameters for \CFA style routine definitions, \eg:1716 \begin{cfa}1717 [ int ] f( * int, int * ); §\C{// returns an integer, accepts 2 pointers to integers}§1718 [ * int, int * ] f( int ); §\C{// returns 2 pointers to integers, accepts an integer}§1719 \end{cfa}1720 The reason for allowing both declaration styles in the new context is for backwards compatibility with existing preprocessor macros that generate C-style declaration-syntax, as in:1721 \begin{cfa}1722 #define ptoa( n, d ) int (*n)[ d ]1723 int f( ptoa( p, 5 ) ) ... §\C{// expands to int f( int (*p)[ 5 ] )}§1724 [ int ] f( ptoa( p, 5 ) ) ... §\C{// expands to [ int ] f( int (*p)[ 5 ] )}§1725 \end{cfa}1726 Again, programmers are highly encouraged to use one declaration form or the other, rather than mixing the forms.1727 1728 1729 \subsection{Named Return Values}1730 1731 \Index{Named return values} handle the case where it is necessary to define a local variable whose value is then returned in a ©return© statement, as in:1732 \begin{cfa}1733 int f() {1734 int x;1735 ... x = 0; ... x = y; ...1736 return x;1737 }1738 \end{cfa}1739 Because the value in the return variable is automatically returned when a \CFA routine terminates, the ©return© statement \emph{does not} contain an expression, as in:1740 \newline1741 \begin{minipage}{\linewidth}1742 \begin{cfa}1743 ®[ int x, int y ]® f() {1744 int z;1745 ... x = 0; ... y = z; ...1746 ®return;® §\C{// implicitly return x, y}§1747 }1748 \end{cfa}1749 \end{minipage}1750 \newline1751 When the return is encountered, the current values of ©x© and ©y© are returned to the calling routine.1752 As well, ``falling off the end'' of a routine without a ©return© statement is permitted, as in:1753 \begin{cfa}1754 [ int x, int y ] f() {1755 ...1756 } §\C{// implicitly return x, y}§1757 \end{cfa}1758 In this case, the current values of ©x© and ©y© are returned to the calling routine just as if a ©return© had been encountered.1759 1760 Named return values may be used in conjunction with named parameter values;1761 specifically, a return and parameter can have the same name.1762 \begin{cfa}1763 [ int x, int y ] f( int, x, int y ) {1764 ...1765 } §\C{// implicitly return x, y}§1766 \end{cfa}1767 This notation allows the compiler to eliminate temporary variables in nested routine calls.1768 \begin{cfa}1769 [ int x, int y ] f( int, x, int y ); §\C{// prototype declaration}§1770 int a, b;1771 [a, b] = f( f( f( a, b ) ) );1772 \end{cfa}1773 While the compiler normally ignores parameters names in prototype declarations, here they are used to eliminate temporary return-values by inferring that the results of each call are the inputs of the next call, and ultimately, the left-hand side of the assignment.1774 Hence, even without the body of routine ©f© (separate compilation), it is possible to perform a global optimization across routine calls.1775 The compiler warns about naming inconsistencies between routine prototype and definition in this case, and behaviour is \Index{undefined} if the programmer is inconsistent.1776 1777 1778 \subsection{Routine Prototype}1779 1780 The syntax of the new routine prototype declaration follows directly from the new routine definition syntax;1781 as well, parameter names are optional, \eg:1782 \begin{cfa}1783 [ int x ] f (); §\C{// returning int with no parameters}§1784 [ * int ] g (int y); §\C{// returning pointer to int with int parameter}§1785 [ ] h ( int, char ); §\C{// returning no result with int and char parameters}§1786 [ * int, int ] j ( int ); §\C{// returning pointer to int and int, with int parameter}§1787 \end{cfa}1788 This syntax allows a prototype declaration to be created by cutting and pasting source text from the routine definition header (or vice versa).1789 It is possible to declare multiple routine-prototypes in a single declaration, but the entire type specification is distributed across \emph{all} routine names in the declaration list (see~\VRef{s:Declarations}), \eg:1790 \begin{quote2}1791 \begin{tabular}{@{}l@{\hspace{3em}}l@{}}1792 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\1793 \begin{cfa}1794 [ int ] f( int ), g;1795 \end{cfa}1796 &1797 \begin{cfa}1798 int f( int ), g( int );1799 \end{cfa}1800 \end{tabular}1801 \end{quote2}1802 Declaration qualifiers can only appear at the start of a \CFA routine declaration,\footref{StorageClassSpecifier} \eg:1803 \begin{cfa}1804 extern [ int ] f ( int );1805 static [ int ] g ( int );1806 \end{cfa}1807 1808 1809 \section{Routine Pointers}1810 1811 The syntax for pointers to \CFA routines specifies the pointer name on the right, \eg:1812 \begin{cfa}1813 * [ int x ] () fp; §\C{// pointer to routine returning int with no parameters}§1814 * [ * int ] (int y) gp; §\C{// pointer to routine returning pointer to int with int parameter}§1815 * [ ] (int,char) hp; §\C{// pointer to routine returning no result with int and char parameters}§1816 * [ * int,int ] ( int ) jp; §\C{// pointer to routine returning pointer to int and int, with int parameter}§1817 \end{cfa}1818 While parameter names are optional, \emph{a routine name cannot be specified};1819 for example, the following is incorrect:1820 \begin{cfa}1821 * [ int x ] f () fp; §\C{// routine name "f" is not allowed}§1822 \end{cfa}1823 1824 1825 \section{Named and Default Arguments}1826 1827 Named\index{named arguments}\index{arguments!named} and default\index{default arguments}\index{arguments!default} arguments~\cite{Hardgrave76}\footnote{1828 Francez~\cite{Francez77} proposed a further extension to the named-parameter passing style, which specifies what type of communication (by value, by reference, by name) the argument is passed to the routine.}1829 are two mechanisms to simplify routine call.1830 Both mechanisms are discussed with respect to \CFA.1831 \begin{description}1832 \item[Named (or Keyword) Arguments:]1833 provide the ability to specify an argument to a routine call using the parameter name rather than the position of the parameter.1834 For example, given the routine:1835 \begin{cfa}1836 void p( int x, int y, int z ) {...}1837 \end{cfa}1838 a positional call is:1839 \begin{cfa}1840 p( 4, 7, 3 );1841 \end{cfa}1842 whereas a named (keyword) call may be:1843 \begin{cfa}1844 p( z : 3, x : 4, y : 7 ); §\C{// rewrite $\Rightarrow$ p( 4, 7, 3 )}§1845 \end{cfa}1846 Here the order of the arguments is unimportant, and the names of the parameters are used to associate argument values with the corresponding parameters.1847 The compiler rewrites a named call into a positional call.1848 The advantages of named parameters are:1849 \begin{itemize}1850 \item1851 Remembering the names of the parameters may be easier than the order in the routine definition.1852 \item1853 Parameter names provide documentation at the call site (assuming the names are descriptive).1854 \item1855 Changes can be made to the order or number of parameters without affecting the call (although the call must still be recompiled).1856 \end{itemize}1857 1858 Unfortunately, named arguments do not work in C-style programming-languages because a routine prototype is not required to specify parameter names, nor do the names in the prototype have to match with the actual definition.1859 For example, the following routine prototypes and definition are all valid.1860 \begin{cfa}1861 void p( int, int, int ); §\C{// equivalent prototypes}§1862 void p( int x, int y, int z );1863 void p( int y, int x, int z );1864 void p( int z, int y, int x );1865 void p( int q, int r, int s ) {} §\C{// match with this definition}§1866 \end{cfa}1867 Forcing matching parameter names in routine prototypes with corresponding routine definitions is possible, but goes against a strong tradition in C programming.1868 Alternatively, prototype definitions can be eliminated by using a two-pass compilation, and implicitly creating header files for exports.1869 The former is easy to do, while the latter is more complex.1870 1871 Furthermore, named arguments do not work well in a \CFA-style programming-languages because they potentially introduces a new criteria for type matching.1872 For example, it is technically possible to disambiguate between these two overloaded definitions of ©f© based on named arguments at the call site:1873 \begin{cfa}1874 int f( int i, int j );1875 int f( int x, double y );1876 1877 f( j : 3, i : 4 ); §\C{// 1st f}§1878 f( x : 7, y : 8.1 ); §\C{// 2nd f}§1879 f( 4, 5 ); §\C{// ambiguous call}§1880 \end{cfa}1881 However, named arguments compound routine resolution in conjunction with conversions:1882 \begin{cfa}1883 f( i : 3, 5.7 ); §\C{// ambiguous call ?}§1884 \end{cfa}1885 Depending on the cost associated with named arguments, this call could be resolvable or ambiguous.1886 Adding named argument into the routine resolution algorithm does not seem worth the complexity.1887 Therefore, \CFA does \emph{not} attempt to support named arguments.1888 1889 \item[Default Arguments]1890 provide the ability to associate a default value with a parameter so it can be optionally specified in the argument list.1891 For example, given the routine:1892 \begin{cfa}1893 void p( int x = 1, int y = 2, int z = 3 ) {...}1894 \end{cfa}1895 the allowable positional calls are:1896 \begin{cfa}1897 p(); §\C{// rewrite $\Rightarrow$ p( 1, 2, 3 )}§1898 p( 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 2, 3 )}§1899 p( 4, 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 4, 3 )}§1900 p( 4, 4, 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 4, 4 )}§1901 // empty arguments1902 p( , 4, 4 ); §\C{// rewrite $\Rightarrow$ p( 1, 4, 4 )}§1903 p( 4, , 4 ); §\C{// rewrite $\Rightarrow$ p( 4, 2, 4 )}§1904 p( 4, 4, ); §\C{// rewrite $\Rightarrow$ p( 4, 4, 3 )}§1905 p( 4, , ); §\C{// rewrite $\Rightarrow$ p( 4, 2, 3 )}§1906 p( , 4, ); §\C{// rewrite $\Rightarrow$ p( 1, 4, 3 )}§1907 p( , , 4 ); §\C{// rewrite $\Rightarrow$ p( 1, 2, 4 )}§1908 p( , , ); §\C{// rewrite $\Rightarrow$ p( 1, 2, 3 )}§1909 \end{cfa}1910 Here the missing arguments are inserted from the default values in the parameter list.1911 The compiler rewrites missing default values into explicit positional arguments.1912 The advantages of default values are:1913 \begin{itemize}1914 \item1915 Routines with a large number of parameters are often very generalized, giving a programmer a number of different options on how a computation is performed.1916 For many of these kinds of routines, there are standard or default settings that work for the majority of computations.1917 Without default values for parameters, a programmer is forced to specify these common values all the time, resulting in long argument lists that are error prone.1918 \item1919 When a routine's interface is augmented with new parameters, it extends the interface providing generalizability\footnote{1920 ``It should be possible for the implementor of an abstraction to increase its generality.1921 So long as the modified abstraction is a generalization of the original, existing uses of the abstraction will not require change.1922 It might be possible to modify an abstraction in a manner which is not a generalization without affecting existing uses, but, without inspecting the modules in which the uses occur, this possibility cannot be determined.1923 This criterion precludes the addition of parameters, unless these parameters have default or inferred values that are valid for all possible existing applications.''~\cite[p.~128]{Cormack90}}1924 (somewhat like the generalization provided by inheritance for classes).1925 That is, all existing calls are still valid, although the call must still be recompiled.1926 \end{itemize}1927 The only disadvantage of default arguments is that unintentional omission of an argument may not result in a compiler-time error.1928 Instead, a default value is used, which may not be the programmer's intent.1929 1930 Default values may only appear in a prototype versus definition context:1931 \begin{cfa}1932 void p( int x, int y = 2, int z = 3 ); §\C{// prototype: allowed}§1933 void p( int, int = 2, int = 3 ); §\C{// prototype: allowed}§1934 void p( int x, int y = 2, int z = 3 ) {} §\C{// definition: not allowed}§1935 \end{cfa}1936 The reason for this restriction is to allow separate compilation.1937 Multiple prototypes with different default values is an error.1938 \end{description}1939 1940 Ellipse (``...'') arguments present problems when used with default arguments.1941 The conflict occurs because both named and ellipse arguments must appear after positional arguments, giving two possibilities:1942 \begin{cfa}1943 p( /* positional */, ... , /* named */ );1944 p( /* positional */, /* named */, ... );1945 \end{cfa}1946 While it is possible to implement both approaches, the first possibly is more complex than the second, \eg:1947 \begin{cfa}1948 p( int x, int y, int z, ... );1949 p( 1, 4, 5, 6, z : 3, y : 2 ); §\C{// assume p( /* positional */, ... , /* named */ );}§1950 p( 1, z : 3, y : 2, 4, 5, 6 ); §\C{// assume p( /* positional */, /* named */, ... );}§1951 \end{cfa}1952 In the first call, it is necessary for the programmer to conceptually rewrite the call, changing named arguments into positional, before knowing where the ellipse arguments begin.1953 Hence, this approach seems significantly more difficult, and hence, confusing and error prone.1954 In the second call, the named arguments separate the positional and ellipse arguments, making it trivial to read the call.1955 1956 The problem is exacerbated with default arguments, \eg:1957 \begin{cfa}1958 void p( int x, int y = 2, int z = 3... );1959 p( 1, 4, 5, 6, z : 3 ); §\C{// assume p( /* positional */, ... , /* named */ );}§1960 p( 1, z : 3, 4, 5, 6 ); §\C{// assume p( /* positional */, /* named */, ... );}§1961 \end{cfa}1962 The first call is an error because arguments 4 and 5 are actually positional not ellipse arguments;1963 therefore, argument 5 subsequently conflicts with the named argument z : 3.1964 In the second call, the default value for y is implicitly inserted after argument 1 and the named arguments separate the positional and ellipse arguments, making it trivial to read the call.1965 For these reasons, \CFA requires named arguments before ellipse arguments.1966 Finally, while ellipse arguments are needed for a small set of existing C routines, like printf, the extended \CFA type system largely eliminates the need for ellipse arguments (see Section 24), making much of this discussion moot.1967 1968 Default arguments and overloading (see Section 24) are complementary.1969 While in theory default arguments can be simulated with overloading, as in:1970 \begin{quote2}1971 \begin{tabular}{@{}l@{\hspace{3em}}l@{}}1972 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{default arguments}} & \multicolumn{1}{c}{\textbf{overloading}} \\1973 \begin{cfa}1974 void p( int x, int y = 2, int z = 3 ) {...}1975 1976 1977 \end{cfa}1978 &1979 \begin{cfa}1980 void p( int x, int y, int z ) {...}1981 void p( int x ) { p( x, 2, 3 ); }1982 void p( int x, int y ) { p( x, y, 3 ); }1983 \end{cfa}1984 \end{tabular}1985 \end{quote2}1986 the number of required overloaded routines is linear in the number of default values, which is unacceptable growth.1987 In general, overloading should only be used over default arguments if the body of the routine is significantly different.1988 Furthermore, overloading cannot handle accessing default arguments in the middle of a positional list, via a missing argument, such as:1989 \begin{cfa}1990 p( 1, /* default */, 5 ); §\C{// rewrite $\Rightarrow$ p( 1, 2, 5 )}§1991 \end{cfa}1992 1993 Given the \CFA restrictions above, both named and default arguments are backwards compatible.1994 \Index*[C++]{\CC{}} only supports default arguments;1995 \Index*{Ada} supports both named and default arguments.1996 1997 1998 \section{Unnamed Structure Fields}1999 2000 C requires each field of a structure to have a name, except for a bit field associated with a basic type, \eg:2001 \begin{cfa}2002 struct {2003 int f1; §\C{// named field}§2004 int f2 : 4; §\C{// named field with bit field size}§2005 int : 3; §\C{// unnamed field for basic type with bit field size}§2006 int ; §\C{// disallowed, unnamed field}§2007 int *; §\C{// disallowed, unnamed field}§2008 int (*)( int ); §\C{// disallowed, unnamed field}§2009 };2010 \end{cfa}2011 This requirement is relaxed by making the field name optional for all field declarations; therefore, all the field declarations in the example are allowed.2012 As for unnamed bit fields, an unnamed field is used for padding a structure to a particular size.2013 A list of unnamed fields is also supported, \eg:2014 \begin{cfa}2015 struct {2016 int , , ; §\C{// 3 unnamed fields}§2017 }2018 \end{cfa}2019 2020 2021 \section{Nesting}2022 2023 Nesting of types and routines is useful for controlling name visibility (\newterm{name hiding}).2024 2025 2026 \subsection{Type Nesting}2027 2028 \CFA allows \Index{type nesting}, and type qualification of the nested types (see \VRef[Figure]{f:TypeNestingQualification}), where as C hoists\index{type hoisting} (refactors) nested types into the enclosing scope and has no type qualification.2029 \begin{figure}2030 \centering2031 \begin{tabular}{@{}l@{\hspace{3em}}l|l@{}}2032 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{C Type Nesting}} & \multicolumn{1}{c}{\textbf{C Implicit Hoisting}} & \multicolumn{1}{|c}{\textbf{\CFA}} \\2033 \hline2034 \begin{cfa}2035 struct S {2036 enum C { R, G, B };2037 struct T {2038 union U { int i, j; };2039 enum C c;2040 short int i, j;2041 };2042 struct T t;2043 } s;2044 2045 int fred() {2046 s.t.c = R;2047 struct T t = { R, 1, 2 };2048 enum C c;2049 union U u;2050 }2051 \end{cfa}2052 &2053 \begin{cfa}2054 enum C { R, G, B };2055 union U { int i, j; };2056 struct T {2057 enum C c;2058 short int i, j;2059 };2060 struct S {2061 struct T t;2062 } s;2063 2064 2065 2066 2067 2068 2069 2070 \end{cfa}2071 &2072 \begin{cfa}2073 struct S {2074 enum C { R, G, B };2075 struct T {2076 union U { int i, j; };2077 enum C c;2078 short int i, j;2079 };2080 struct T t;2081 } s;2082 2083 int fred() {2084 s.t.c = ®S.®R; // type qualification2085 struct ®S.®T t = { ®S.®R, 1, 2 };2086 enum ®S.®C c;2087 union ®S.T.®U u;2088 }2089 \end{cfa}2090 \end{tabular}2091 \caption{Type Nesting / Qualification}2092 \label{f:TypeNestingQualification}2093 \end{figure}2094 In the left example in C, types ©C©, ©U© and ©T© are implicitly hoisted outside of type ©S© into the containing block scope.2095 In the right example in \CFA, the types are not hoisted and accessed using the field-selection operator ``©.©'' for type qualification, as does \Index*{Java}, rather than the \CC type-selection operator ``©::©''.2096 2097 2098 \subsection{Routine Nesting}2099 2100 While \CFA does not provide object programming by putting routines into structures, it does rely heavily on locally nested routines to redefine operations at or close to a call site.2101 For example, the C quick-sort is wrapped into the following polymorphic \CFA routine:2102 \begin{cfa}2103 forall( otype T | { int ?<?( T, T ); } )2104 void qsort( const T * arr, size_t dimension );2105 \end{cfa}2106 which can be used to sort in ascending and descending order by locally redefining the less-than operator into greater-than.2107 \begin{cfa}2108 const unsigned int size = 5;2109 int ia[size];2110 ... §\C{// assign values to array ia}§2111 qsort( ia, size ); §\C{// sort ascending order using builtin ?<?}§2112 {2113 ®int ?<?( int x, int y ) { return x > y; }® §\C{// nested routine}§2114 qsort( ia, size ); §\C{// sort descending order by local redefinition}§2115 }2116 \end{cfa}2117 2118 Nested routines are not first-class, meaning a nested routine cannot be returned if it has references to variables in its enclosing blocks;2119 the only exception is references to the external block of the translation unit, as these variables persist for the duration of the program.2120 The following program in undefined in \CFA (and Indexc{gcc})2121 \begin{cfa}2122 [* [int]( int )] foo() { §\C{// int (*foo())( int )}§2123 int ®i® = 7;2124 int bar( int p ) {2125 ®i® += 1; §\C{// dependent on local variable}§2126 sout | ®i® | endl;2127 }2128 return bar; §\C{// undefined because of local dependence}§2129 }2130 int main() {2131 * [int]( int ) fp = foo(); §\C{// int (*fp)( int )}§2132 sout | fp( 3 ) | endl;2133 }2134 \end{cfa}2135 because2136 2137 Currently, there are no \Index{lambda} expressions, \ie unnamed routines because routine names are very important to properly select the correct routine.2138 2139 2140 \section{Tuples}2141 2142 In C and \CFA, lists of elements appear in several contexts, such as the parameter list for a routine call.2143 (More contexts are added shortly.)2144 A list of such elements is called a \newterm{lexical list}.2145 The general syntax of a lexical list is:2146 \begin{cfa}2147 [ §\emph{exprlist}§ ]2148 \end{cfa}2149 where ©$\emph{exprlist}$© is a list of one or more expressions separated by commas.2150 The brackets, ©[]©, allow differentiating between lexical lists and expressions containing the C comma operator.2151 The following are examples of lexical lists:2152 \begin{cfa}2153 [ x, y, z ]2154 [ 2 ]2155 [ v+w, x*y, 3.14159, f() ]2156 \end{cfa}2157 Tuples are permitted to contain sub-tuples (\ie nesting), such as ©[ [ 14, 21 ], 9 ]©, which is a 2-element tuple whose first element is itself a tuple.2158 Note, a tuple is not a record (structure);2159 a record denotes a single value with substructure, whereas a tuple is multiple values with no substructure (see flattening coercion in Section 12.1).2160 In essence, tuples are largely a compile time phenomenon, having little or no runtime presence.2161 2162 Tuples can be organized into compile-time tuple variables;2163 these variables are of \newterm{tuple type}.2164 Tuple variables and types can be used anywhere lists of conventional variables and types can be used.2165 The general syntax of a tuple type is:2166 \begin{cfa}2167 [ §\emph{typelist}§ ]2168 \end{cfa}2169 where ©$\emph{typelist}$© is a list of one or more legal \CFA or C type specifications separated by commas, which may include other tuple type specifications.2170 Examples of tuple types include:2171 \begin{cfa}2172 [ unsigned int, char ]2173 [ double, double, double ]2174 [ * int, int * ] §\C{// mix of CFA and ANSI}§2175 [ * [ 5 ] int, * * char, * [ [ int, int ] ] (int, int) ]2176 \end{cfa}2177 Like tuples, tuple types may be nested, such as ©[ [ int, int ], int ]©, which is a 2-element tuple type whose first element is itself a tuple type.2178 2179 Examples of declarations using tuple types are:2180 \begin{cfa}2181 [ int, int ] x; §\C{// 2 element tuple, each element of type int}§2182 * [ char, char ] y; §\C{// pointer to a 2 element tuple}§2183 [ [ int, int ] ] z ([ int, int ]);2184 \end{cfa}2185 The last example declares an external routine that expects a 2 element tuple as an input parameter and returns a 2 element tuple as its result.2186 2187 As mentioned, tuples can appear in contexts requiring a list of value, such as an argument list of a routine call.2188 In unambiguous situations, the tuple brackets may be omitted, \eg a tuple that appears as an argument may have its2189 square brackets omitted for convenience; therefore, the following routine invocations are equivalent:2190 \begin{cfa}2191 f( [ 1, x+2, fred() ] );2192 f( 1, x+2, fred() );2193 \end{cfa}2194 Also, a tuple or a tuple variable may be used to supply all or part of an argument list for a routine expecting multiple input parameters or for a routine expecting a tuple as an input parameter.2195 For example, the following are all legal:2196 \begin{cfa}2197 [ int, int ] w1;2198 [ int, int, int ] w2;2199 [ void ] f (int, int, int); /* three input parameters of type int */2200 [ void ] g ([ int, int, int ]); /* 3 element tuple as input */2201 f( [ 1, 2, 3 ] );2202 f( w1, 3 );2203 f( 1, w1 );2204 f( w2 );2205 g( [ 1, 2, 3 ] );2206 g( w1, 3 );2207 g( 1, w1 );2208 g( w2 );2209 \end{cfa}2210 Note, in all cases 3 arguments are supplied even though the syntax may appear to supply less than 3. As mentioned, a2211 tuple does not have structure like a record; a tuple is simply converted into a list of components.2212 \begin{rationale}2213 The present implementation of \CFA does not support nested routine calls when the inner routine returns multiple values; \ie a statement such as ©g( f() )© is not supported.2214 Using a temporary variable to store the results of the inner routine and then passing this variable to the outer routine works, however.2215 \end{rationale}2216 2217 A tuple can contain a C comma expression, provided the expression containing the comma operator is enclosed in parentheses.2218 For instance, the following tuples are equivalent:2219 \begin{cfa}2220 [ 1, 3, 5 ]2221 [ 1, (2, 3), 5 ]2222 \end{cfa}2223 The second element of the second tuple is the expression (2, 3), which yields the result 3.2224 This requirement is the same as for comma expressions in argument lists.2225 2226 Type qualifiers, \ie const and volatile, may modify a tuple type.2227 The meaning is the same as for a type qualifier modifying an aggregate type [Int99, x 6.5.2.3(7),x 6.7.3(11)], \ie the qualifier is distributed across all of the types in the tuple, \eg:2228 \begin{cfa}2229 const volatile [ int, float, const int ] x;2230 \end{cfa}2231 is equivalent to:2232 \begin{cfa}2233 [ const volatile int, const volatile float, const volatile int ] x;2234 \end{cfa}2235 Declaration qualifiers can only appear at the start of a \CFA tuple declaration4, \eg:2236 \begin{cfa}2237 extern [ int, int ] w1;2238 static [ int, int, int ] w2;2239 \end{cfa}2240 \begin{rationale}2241 Unfortunately, C's syntax for subscripts precluded treating them as tuples.2242 The C subscript list has the form ©[i][j]...© and not ©[i, j, ...]©.2243 Therefore, there is no syntactic way for a routine returning multiple values to specify the different subscript values, \eg ©f[g()]© always means a single subscript value because there is only one set of brackets.2244 Fixing this requires a major change to C because the syntactic form ©M[i, j, k]© already has a particular meaning: ©i, j, k© is a comma expression.2245 \end{rationale}2246 2247 2248 \subsection{Tuple Coercions}2249 2250 There are four coercions that can be performed on tuples and tuple variables: closing, opening, flattening and structuring.2251 In addition, the coercion of dereferencing can be performed on a tuple variable to yield its value(s), as for other variables.2252 A \newterm{closing coercion} takes a set of values and converts it into a tuple value, which is a contiguous set of values, as in:2253 \begin{cfa}2254 [ int, int, int, int ] w;2255 w = [ 1, 2, 3, 4 ];2256 \end{cfa}2257 First the right-hand tuple is closed into a tuple value and then the tuple value is assigned.2258 2259 An \newterm{opening coercion} is the opposite of closing; a tuple value is converted into a tuple of values, as in:2260 \begin{cfa}2261 [ a, b, c, d ] = w2262 \end{cfa}2263 ©w© is implicitly opened to yield a tuple of four values, which are then assigned individually.2264 2265 A \newterm{flattening coercion} coerces a nested tuple, \ie a tuple with one or more components, which are themselves tuples, into a flattened tuple, which is a tuple whose components are not tuples, as in:2266 \begin{cfa}2267 [ a, b, c, d ] = [ 1, [ 2, 3 ], 4 ];2268 \end{cfa}2269 First the right-hand tuple is flattened and then the values are assigned individually.2270 Flattening is also performed on tuple types.2271 For example, the type ©[ int, [ int, int ], int ]© can be coerced, using flattening, into the type ©[ int, int, int, int ]©.2272 2273 A \newterm{structuring coercion} is the opposite of flattening;2274 a tuple is structured into a more complex nested tuple.2275 For example, structuring the tuple ©[ 1, 2, 3, 4 ]© into the tuple ©[ 1, [ 2, 3 ], 4 ]© or the tuple type ©[ int, int, int, int ]© into the tuple type ©[ int, [ int, int ], int ]©.2276 In the following example, the last assignment illustrates all the tuple coercions:2277 \begin{cfa}2278 [ int, int, int, int ] w = [ 1, 2, 3, 4 ];2279 int x = 5;2280 [ x, w ] = [ w, x ]; §\C{// all four tuple coercions}§2281 \end{cfa}2282 Starting on the right-hand tuple in the last assignment statement, w is opened, producing a tuple of four values;2283 therefore, the right-hand tuple is now the tuple ©[ [ 1, 2, 3, 4 ], 5 ]©.2284 This tuple is then flattened, yielding ©[ 1, 2, 3, 4, 5 ]©, which is structured into ©[ 1, [ 2, 3, 4, 5 ] ]© to match the tuple type of the left-hand side.2285 The tuple ©[ 2, 3, 4, 5 ]© is then closed to create a tuple value.2286 Finally, ©x© is assigned ©1© and ©w© is assigned the tuple value using multiple assignment (see Section 14).2287 \begin{rationale}2288 A possible additional language extension is to use the structuring coercion for tuples to initialize a complex record with a tuple.2289 \end{rationale}2290 2291 2292 \section{Mass Assignment}2293 2294 \CFA permits assignment to several variables at once using mass assignment~\cite{CLU}.2295 Mass assignment has the following form:2296 \begin{cfa}2297 [ §\emph{lvalue}§, ... , §\emph{lvalue}§ ] = §\emph{expr}§;2298 \end{cfa}2299 \index{lvalue}2300 The left-hand side is a tuple of \emph{lvalues}, which is a list of expressions each yielding an address, \ie any data object that can appear on the left-hand side of a conventional assignment statement.2301 ©$\emph{expr}$© is any standard arithmetic expression.2302 Clearly, the types of the entities being assigned must be type compatible with the value of the expression.2303 2304 Mass assignment has parallel semantics, \eg the statement:2305 \begin{cfa}2306 [ x, y, z ] = 1.5;2307 \end{cfa}2308 is equivalent to:2309 \begin{cfa}2310 x = 1.5; y = 1.5; z = 1.5;2311 \end{cfa}2312 This semantics is not the same as the following in C:2313 \begin{cfa}2314 x = y = z = 1.5;2315 \end{cfa}2316 as conversions between intermediate assignments may lose information.2317 A more complex example is:2318 \begin{cfa}2319 [ i, y[i], z ] = a + b;2320 \end{cfa}2321 which is equivalent to:2322 \begin{cfa}2323 t = a + b;2324 a1 = &i; a2 = &y[i]; a3 = &z;2325 *a1 = t; *a2 = t; *a3 = t;2326 \end{cfa}2327 The temporary ©t© is necessary to store the value of the expression to eliminate conversion issues.2328 The temporaries for the addresses are needed so that locations on the left-hand side do not change as the values are assigned.2329 In this case, ©y[i]© uses the previous value of ©i© and not the new value set at the beginning of the mass assignment.2330 2331 2332 \section{Multiple Assignment}2333 2334 \CFA also supports the assignment of several values at once, known as multiple assignment~\cite{CLU,Galletly96}.2335 Multiple assignment has the following form:2336 \begin{cfa}2337 [ §\emph{lvalue}§, ... , §\emph{lvalue}§ ] = [ §\emph{expr}§, ... , §\emph{expr}§ ];2338 \end{cfa}2339 \index{lvalue}2340 The left-hand side is a tuple of \emph{lvalues}, and the right-hand side is a tuple of \emph{expr}s.2341 Each \emph{expr} appearing on the right-hand side of a multiple assignment statement is assigned to the corresponding \emph{lvalues} on the left-hand side of the statement using parallel semantics for each assignment.2342 An example of multiple assignment is:2343 \begin{cfa}2344 [ x, y, z ] = [ 1, 2, 3 ];2345 \end{cfa}2346 Here, the values ©1©, ©2© and ©3© are assigned, respectively, to the variables ©x©, ©y© and ©z©.2347 A more complex example is:2348 \begin{cfa}2349 [ i, y[ i ], z ] = [ 1, i, a + b ];2350 \end{cfa}2351 Here, the values ©1©, ©i© and ©a + b© are assigned to the variables ©i©, ©y[i]© and ©z©, respectively.2352 Note, the parallel semantics of2353 multiple assignment ensures:2354 \begin{cfa}2355 [ x, y ] = [ y, x ];2356 \end{cfa}2357 correctly interchanges (swaps) the values stored in ©x© and ©y©.2358 The following cases are errors:2359 \begin{cfa}2360 [ a, b, c ] = [ 1, 2, 3, 4 ];2361 [ a, b, c ] = [ 1, 2 ];2362 \end{cfa}2363 because the number of entities in the left-hand tuple is unequal with the right-hand tuple.2364 2365 As for all tuple contexts in C, side effects should not be used because C does not define an ordering for the evaluation of the elements of a tuple;2366 both these examples produce indeterminate results:2367 \begin{cfa}2368 f( x++, x++ ); §\C{// C routine call with side effects in arguments}§2369 [ v1, v2 ] = [ x++, x++ ]; §\C{// side effects in righthand side of multiple assignment}§2370 \end{cfa}2371 2372 2373 \section{Cascade Assignment}2374 2375 As in C, \CFA mass and multiple assignments can be cascaded, producing cascade assignment.2376 Cascade assignment has the following form:2377 \begin{cfa}2378 §\emph{tuple}§ = §\emph{tuple}§ = ... = §\emph{tuple}§;2379 \end{cfa}2380 and it has the same parallel semantics as for mass and multiple assignment.2381 Some examples of cascade assignment are:2382 \begin{cfa}2383 x1 = y1 = x2 = y2 = 0;2384 [ x1, y1 ] = [ x2, y2 ] = [ x3, y3 ];2385 [ x1, y1 ] = [ x2, y2 ] = 0;2386 [ x1, y1 ] = z = 0;2387 \end{cfa}2388 As in C, the rightmost assignment is performed first, \ie assignment parses right to left.2389 2390 2391 \section{Field Tuples}2392 2393 Tuples may be used to select multiple fields of a record by field name.2394 Its general form is:2395 \begin{cfa}2396 §\emph{expr}§ . [ §\emph{fieldlist}§ ]2397 §\emph{expr}§ -> [ §\emph{fieldlist}§ ]2398 \end{cfa}2399 \emph{expr} is any expression yielding a value of type record, \eg ©struct©, ©union©.2400 Each element of \emph{ fieldlist} is an element of the record specified by \emph{expr}.2401 A record-field tuple may be used anywhere a tuple can be used. An example of the use of a record-field tuple is2402 the following:2403 \begin{cfa}2404 struct s {2405 int f1, f2;2406 char f3;2407 double f4;2408 } v;2409 v.[ f3, f1, f2 ] = ['x', 11, 17 ]; §\C{// equivalent to v.f3 = 'x', v.f1 = 11, v.f2 = 17}§2410 f( v.[ f3, f1, f2 ] ); §\C{// equivalent to f( v.f3, v.f1, v.f2 )}§2411 \end{cfa}2412 Note, the fields appearing in a record-field tuple may be specified in any order;2413 also, it is unnecessary to specify all the fields of a struct in a multiple record-field tuple.2414 2415 If a field of a ©struct© is itself another ©struct©, multiple fields of this subrecord can be specified using a nested record-field tuple, as in the following example:2416 \begin{cfa}2417 struct inner {2418 int f2, f3;2419 };2420 struct outer {2421 int f1;2422 struct inner i;2423 double f4;2424 } o;2425 2426 o.[ f1, i.[ f2, f3 ], f4 ] = [ 11, 12, 13, 3.14159 ];2427 \end{cfa}2428 2429 2430 2399 \section{I/O Library} 2431 2400 \label{s:IOLibrary} … … 2433 2402 2434 2403 The goal of \CFA I/O is to simplify the common cases\index{I/O!common case}, while fully supporting polymorphism and user defined types in a consistent way. 2435 The approach combines ideas from \CC and Python.2436 2404 The \CFA header file for the I/O library is \Indexc{fstream}. 2437 2405 … … 2451 2419 \\ 2452 2420 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt] 2453 1 ® ®2® ®32421 1 2 3 2454 2422 \end{cfa} 2455 2423 & … … 2459 2427 \end{tabular} 2460 2428 \end{quote2} 2461 The \CFA form has half the characters ofthe \CC form, and is similar to \Index*{Python} I/O with respect to implicit separators.2462 Similar simplification occurs for \Index{tuple} I/O, which prints all tuple values separated by ``\lstinline[showspaces=true]@, @''.2429 The \CFA form has half as many characters as the \CC form, and is similar to \Index*{Python} I/O with respect to implicit separators. 2430 A tuple prints all the tuple's values, each separated by ©", "©. 2463 2431 \begin{cfa}[mathescape=off,aboveskip=0pt,belowskip=0pt] 2464 [int, [ int, int ] ] t1 = [ 1, [ 2, 3 ] ], t2 = [ 3, [ 4, 5 ]];2432 [int, int] t1 = [1, 2], t2 = [3, 4]; 2465 2433 sout | t1 | t2 | endl; §\C{// print tuples}§ 2466 2434 \end{cfa} 2467 2435 \begin{cfa}[mathescape=off,showspaces=true,belowskip=0pt] 2468 1 ®, ®2®, ®3 3®, ®4®, ®52469 \end{cfa} 2470 Finally, \CFA uses the logical-or operator for I/O asit is the lowest-priority overloadable operator, other than assignment.2436 1, 2, 3, 4 2437 \end{cfa} 2438 \CFA uses the logical-or operator for I/O because it is the lowest-priority overloadable operator, other than assignment. 2471 2439 Therefore, fewer output expressions require parenthesis. 2472 2440 \begin{quote2} … … 2490 2458 \end{tabular} 2491 2459 \end{quote2} 2492 There is a weak similarity between the \CFA logical-or operator and the Shell pipe-operator for moving data, where data flows in the correct direction for input but the opposite direction for output. 2493 2494 2495 \subsection{Implicit Separator} 2496 2497 The \Index{implicit separator}\index{I/O!separator} character (space/blank) is a separator not a terminator. 2460 Finally, the logical-or operator has a link with the Shell pipe-operator for moving data, where data flows in the correct direction for input but the opposite direction for output. 2461 2462 2463 The implicit separator\index{I/O!separator} character (space/blank) is a separator not a terminator. 2498 2464 The rules for implicitly adding the separator are: 2499 2465 \begin{enumerate} … … 2567 2533 \end{enumerate} 2568 2534 2569 2570 \subsection{Manipulator}2571 2572 2535 The following routines and \CC-style \Index{manipulator}s control implicit seperation. 2573 2536 \begin{enumerate} … … 2581 2544 %$ 2582 2545 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt] 2583 1 ®, $®2®, $®3 ®", $"®2546 1, $2, $3 ®", $"® 2584 2547 \end{cfa} 2585 2548 %$ … … 2589 2552 \end{cfa} 2590 2553 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt] 2591 1® ®2® ®3 ®" "® 2554 1 2 3 ®" "® 2555 \end{cfa} 2556 2557 \item 2558 Manipulators \Indexc{sepOn}\index{manipulator!sepOn@©sepOn©} and \Indexc{sepOff}\index{manipulator!sepOff@©sepOff©} \emph{locally} toggle printing the separator, \ie the seperator is adjusted only with respect to the next printed item. 2559 \begin{cfa}[mathescape=off,belowskip=0pt] 2560 sout | sepOn | 1 | 2 | 3 | sepOn | endl; §\C{// separator at start of line}§ 2561 \end{cfa} 2562 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt] 2563 1 2 3 2564 \end{cfa} 2565 \begin{cfa}[mathescape=off,aboveskip=0pt,belowskip=0pt] 2566 sout | 1 | sepOff | 2 | 3 | endl; §\C{// locally turn off implicit separator}§ 2567 \end{cfa} 2568 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt] 2569 12 3 2570 \end{cfa} 2571 2572 \item 2573 Manipulators \Indexc{sepDisable}\index{manipulator!sepDisable@©sepDisable©} and \Indexc{sepEnable}\index{manipulator!sepEnable@©sepEnable©} \emph{globally} toggle printing the separator, \ie the seperator is adjusted with respect to all subsequent printed items, unless locally adjusted. 2574 \begin{cfa}[mathescape=off,aboveskip=0pt,belowskip=0pt] 2575 sout | sepDisable | 1 | 2 | 3 | endl; §\C{// globally turn off implicit separation}§ 2576 \end{cfa} 2577 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt] 2578 123 2579 \end{cfa} 2580 \begin{cfa}[mathescape=off,aboveskip=0pt,belowskip=0pt] 2581 sout | 1 | sepOn | 2 | 3 | endl; §\C{// locally turn on implicit separator}§ 2582 \end{cfa} 2583 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt] 2584 1 23 2585 \end{cfa} 2586 \begin{cfa}[mathescape=off,aboveskip=0pt,belowskip=0pt] 2587 sout | sepEnable | 1 | 2 | 3 | endl; §\C{// globally turn on implicit separation}§ 2588 \end{cfa} 2589 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt] 2590 1 2 3 2592 2591 \end{cfa} 2593 2592 … … 2611 2610 2612 2611 \item 2613 Manipulators \Indexc{sepOn}\index{manipulator!sepOn@©sepOn©} and \Indexc{sepOff}\index{manipulator!sepOff@©sepOff©} \emph{locally} toggle printing the separator, \ie the seperator is adjusted only with respect to the next printed item. 2614 \begin{cfa}[mathescape=off,belowskip=0pt] 2615 sout | sepOn | 1 | 2 | 3 | sepOn | endl; §\C{// separator at start/end of line}§ 2616 \end{cfa} 2617 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt] 2618 ® ®1 2 3® ® 2619 \end{cfa} 2620 \begin{cfa}[mathescape=off,aboveskip=0pt,belowskip=0pt] 2621 sout | 1 | sepOff | 2 | 3 | endl; §\C{// locally turn off implicit separator}§ 2622 \end{cfa} 2623 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt] 2624 12 3 2625 \end{cfa} 2626 The tuple separator also responses to being turned on and off. 2612 The tuple separator can also be turned on and off. 2627 2613 \begin{cfa}[mathescape=off,aboveskip=0pt,belowskip=0pt] 2628 2614 sout | sepOn | t1 | sepOff | t2 | endl; §\C{// locally turn on/off implicit separation}§ … … 2632 2618 \end{cfa} 2633 2619 Notice a tuple seperator starts the line because the next item is a tuple. 2634 2635 \item2636 Manipulators \Indexc{sepDisable}\index{manipulator!sepDisable@©sepDisable©} and \Indexc{sepEnable}\index{manipulator!sepEnable@©sepEnable©} \emph{globally} toggle printing the separator, \ie the seperator is adjusted with respect to all subsequent printed items, unless locally adjusted.2637 \begin{cfa}[mathescape=off,aboveskip=0pt,belowskip=0pt]2638 sout | sepDisable | 1 | 2 | 3 | endl; §\C{// globally turn off implicit separation}§2639 \end{cfa}2640 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt]2641 1232642 \end{cfa}2643 \begin{cfa}[mathescape=off,aboveskip=0pt,belowskip=0pt]2644 sout | 1 | ®sepOn® | 2 | 3 | endl; §\C{// locally turn on implicit separator}§2645 \end{cfa}2646 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt]2647 1® ®232648 \end{cfa}2649 \begin{cfa}[mathescape=off,aboveskip=0pt,belowskip=0pt]2650 sout | sepEnable | 1 | 2 | 3 | endl; §\C{// globally turn on implicit separation}§2651 \end{cfa}2652 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt]2653 1 2 32654 \end{cfa}2655 2620 \end{enumerate} 2656 2621 … … 2661 2626 int x = 1, y = 2, z = 3; 2662 2627 sout | x | y | z | endl; 2663 [int, [ int, int ] ] t1 = [ 1, [ 2, 3 ] ], t2 = [ 3, [ 4, 5 ]];2664 sout | t1 | t2 | endl; // print tuple s2628 [int, int] t1 = [1, 2], t2 = [3, 4]; 2629 sout | t1 | t2 | endl; // print tuple 2665 2630 sout | x * 3 | y + 1 | z << 2 | x == y | (x | y) | (x || y) | (x > z ? 1 : 2) | endl; 2666 2631 sout | 1 | 2 | 3 | endl; … … 5224 5189 5225 5190 5226 \section{\ CFA Keywords}5191 \section{\protect\CFA Keywords} 5227 5192 \label{s:CFAKeywords} 5228 5193 … … 5522 5487 For an increase in storage size, new storage after the copied data may be filled. 5523 5488 \item[alignment] 5524 an allocation starts on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.5489 an allocation starts on a specified memory boundary, e.g., an address multiple of 64 or 128 for cache-line purposes. 5525 5490 \item[array] 5526 5491 the allocation size is scaled to the specified number of array elements. -
src/CodeGen/CodeGenerator.cc
r67fa9f9 r11dbfe1 288 288 } 289 289 290 void CodeGenerator:: visit( Designation * designation) {291 std::list< Expression * > designators = designation->get_designators();290 void CodeGenerator::printDesignators( std::list< Expression * > & designators ) { 291 typedef std::list< Expression * > DesignatorList; 292 292 if ( designators.size() == 0 ) return; 293 for ( Expression * des : designators) {294 if ( dynamic_cast< NameExpr * >( des ) || dynamic_cast< VariableExpr * >( des) ) {295 // if expression is a NameExpr or VariableExpr, then initializing aggregate member293 for ( DesignatorList::iterator iter = designators.begin(); iter != designators.end(); ++iter ) { 294 if ( dynamic_cast< NameExpr * >( *iter ) ) { 295 // if expression is a name, then initializing aggregate member 296 296 output << "."; 297 des->accept( *this );297 (*iter)->accept( *this ); 298 298 } else { 299 // otherwise, it has to be a ConstantExpr or CastExpr, initializing array eleemnt299 // if not a simple name, it has to be a constant expression, i.e. an array designator 300 300 output << "["; 301 des->accept( *this );301 (*iter)->accept( *this ); 302 302 output << "]"; 303 303 } // if … … 307 307 308 308 void CodeGenerator::visit( SingleInit * init ) { 309 printDesignators( init->get_designators() ); 309 310 init->get_value()->accept( *this ); 310 311 } 311 312 312 313 void CodeGenerator::visit( ListInit * init ) { 313 auto initBegin = init->begin(); 314 auto initEnd = init->end(); 315 auto desigBegin = init->get_designations().begin(); 316 auto desigEnd = init->get_designations().end(); 317 314 printDesignators( init->get_designators() ); 318 315 output << "{ "; 319 for ( ; initBegin != initEnd && desigBegin != desigEnd; ) { 320 (*desigBegin)->accept( *this ); 321 (*initBegin)->accept( *this ); 322 ++initBegin, ++desigBegin; 323 if ( initBegin != initEnd ) { 324 output << ", "; 325 } 326 } 316 genCommaList( init->begin(), init->end() ); 327 317 output << " }"; 328 assertf( initBegin == initEnd && desigBegin == desigEnd, "Initializers and designators not the same length. %s", toString( init ).c_str() );329 318 } 330 319 … … 727 716 728 717 void CodeGenerator::visit( TypeExpr * typeExpr ) { 729 // if ( genC ) std::cerr << "typeexpr still exists: " << typeExpr << std::endl; 730 // assertf( ! genC, "TypeExpr should not reach code generation." ); 731 if ( ! genC ) { 732 output<< genType( typeExpr->get_type(), "", pretty, genC ); 733 } 718 assertf( ! genC, "TypeExpr should not reach code generation." ); 719 output<< genType( typeExpr->get_type(), "", pretty, genC ); 734 720 } 735 721 -
src/CodeGen/CodeGenerator.h
r67fa9f9 r11dbfe1 47 47 48 48 //*** Initializer 49 virtual void visit( Designation * );50 49 virtual void visit( SingleInit * ); 51 50 virtual void visit( ListInit * ); … … 138 137 bool lineMarks = false; 139 138 139 void printDesignators( std::list< Expression * > & ); 140 140 void handleStorageClass( DeclarationWithType *decl ); 141 141 void handleAggregate( AggregateDecl *aggDecl, const std::string & kind ); -
src/Common/PassVisitor.h
r67fa9f9 r11dbfe1 12 12 #include "SynTree/Expression.h" 13 13 #include "SynTree/Constant.h" 14 #include "SynTree/TypeSubstitution.h"15 14 16 15 #include "PassVisitor.proto.h" … … 27 26 // stmtsToAddBefore or stmtsToAddAfter respectively. 28 27 // | WithShortCircuiting - provides the ability to skip visiting child nodes; set visit_children to false in pre{visit,mutate} to skip visiting children 29 // | With Guards - provides the ability to save/restore data like a LIFO stack; to save, call GuardValue with the variable to save, the variable28 // | WithScopes - provides the ability to save/restore data like a LIFO stack; to save, call GuardValue with the variable to save, the variable 30 29 // will automatically be restored to its previous value after the corresponding postvisit/postmutate teminates. 31 30 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- … … 33 32 class PassVisitor final : public Visitor, public Mutator { 34 33 public: 34 PassVisitor() = default; 35 35 36 36 template< typename... Args > … … 257 257 258 258 void set_visit_children( bool& ref ) { bool_ref * ptr = visit_children_impl(pass, 0); if(ptr) ptr->set( ref ); } 259 260 guard_value_impl init_guard() { 261 guard_value_impl guard; 262 auto at_cleanup = at_cleanup_impl(pass, 0); 263 if( at_cleanup ) { 264 *at_cleanup = [&guard]( cleanup_func_t && func, void* val ) { 265 guard.push( std::move( func ), val ); 266 }; 267 } 268 return guard; 269 } 259 270 }; 260 271 … … 272 283 273 284 public: 274 TypeSubstitution * env = nullptr;285 TypeSubstitution * env; 275 286 }; 276 287 … … 284 295 std::list< Statement* > stmtsToAddAfter; 285 296 }; 286 287 class WithDeclsToAdd {288 protected:289 WithDeclsToAdd() = default;290 ~WithDeclsToAdd() = default;291 292 public:293 std::list< Declaration* > declsToAddBefore;294 std::list< Declaration* > declsToAddAfter;295 };296 297 297 class WithShortCircuiting { 298 298 protected: … … 304 304 }; 305 305 306 class With Guards {307 protected: 308 With Guards() = default;309 ~With Guards() = default;306 class WithScopes { 307 protected: 308 WithScopes() = default; 309 ~WithScopes() = default; 310 310 311 311 public: … … 318 318 }, static_cast< void * >( & val ) ); 319 319 } 320 321 template< typename T >322 void GuardScope( T& val ) {323 val.beginScope();324 at_cleanup( []( void * val ) {325 static_cast< T * >( val )->endScope();326 }, static_cast< void * >( & val ) );327 }328 329 template< typename Func >330 void GuardAction( Func func ) {331 at_cleanup( [func](__attribute__((unused)) void *) { func(); }, nullptr );332 }333 320 }; 334 321 … … 336 323 class WithVisitorRef { 337 324 protected: 338 WithVisitorRef() {}339 ~WithVisitorRef() {}340 341 public: 342 PassVisitor<pass_type> * const visitor = nullptr;325 WithVisitorRef() = default; 326 ~WithVisitorRef() = default; 327 328 public: 329 PassVisitor<pass_type> * const visitor; 343 330 }; 344 331 -
src/Common/PassVisitor.impl.h
r67fa9f9 r11dbfe1 3 3 #define VISIT_START( node ) \ 4 4 __attribute__((unused)) \ 5 guard_value_impl guard( at_cleanup_impl(pass, 0) );\5 const auto & guard = init_guard(); \ 6 6 bool visit_children = true; \ 7 7 set_visit_children( visit_children ); \ … … 15 15 #define MUTATE_START( node ) \ 16 16 __attribute__((unused)) \ 17 guard_value_impl guard( at_cleanup_impl(pass, 0) );\17 const auto & guard = init_guard(); \ 18 18 bool visit_children = true; \ 19 19 set_visit_children( visit_children ); \ … … 68 68 for ( std::list< Declaration* >::iterator i = decls.begin(); ; ++i ) { 69 69 // splice in new declarations after previous decl 70 if ( !empty( afterDecls ) ) { decls.splice( i, *afterDecls ); } 70 if ( !empty( afterDecls ) ) { decls.splice( i, *afterDecls ); } 71 71 72 72 if ( i == decls.end() ) break; … … 88 88 for ( std::list< Declaration* >::iterator i = decls.begin(); ; ++i ) { 89 89 // splice in new declarations after previous decl 90 if ( !empty( afterDecls ) ) { decls.splice( i, *afterDecls ); } 90 if ( !empty( afterDecls ) ) { decls.splice( i, *afterDecls ); } 91 91 92 92 if ( i == decls.end() ) break; … … 104 104 void PassVisitor< pass_type >::handleStatementList( std::list< Statement * > & statements, func_t func ) { 105 105 SemanticError errors; 106 107 // don't want statements from outer CompoundStmts to be added to this CompoundStmt108 ValueGuardPtr< StmtList_t > oldBeforeStmts( get_beforeStmts() );109 ValueGuardPtr< StmtList_t > oldAfterStmts ( get_afterStmts () );110 ValueGuardPtr< DeclList_t > oldBeforeDecls( get_beforeDecls() );111 ValueGuardPtr< DeclList_t > oldAfterDecls ( get_afterDecls () );112 106 113 107 StmtList_t* beforeStmts = get_beforeStmts(); … … 187 181 Statement * PassVisitor< pass_type >::visitStatement( Statement * stmt ) { 188 182 return handleStatement( stmt, [this]( Statement * stmt ) { 189 maybeAccept( stmt, *this ); 183 maybeAccept( stmt, *this ); 190 184 return stmt; 191 185 }); … … 218 212 expr->accept( *this ); 219 213 return expr; 220 }); 214 }); 221 215 } 222 216 … … 571 565 VISIT_START( node ); 572 566 573 // maybeAccept( node->get_env(), *this );574 maybeAccept( node->get_result(), *this );575 576 567 for ( auto expr : node->get_args() ) { 577 568 visitExpression( expr ); … … 584 575 Expression * PassVisitor< pass_type >::mutate( UntypedExpr * node ) { 585 576 MUTATE_START( node ); 586 587 node->set_env( maybeMutate( node->get_env(), *this ) );588 node->set_result( maybeMutate( node->get_result(), *this ) );589 577 590 578 for ( auto& expr : node->get_args() ) { -
src/Common/PassVisitor.proto.h
r67fa9f9 r11dbfe1 5 5 6 6 typedef std::function<void( void * )> cleanup_func_t; 7 typedef std::function< void( cleanup_func_t, void * ) > at_cleanup_t;8 7 9 8 class guard_value_impl { 10 9 public: 11 guard_value_impl( at_cleanup_t * at_cleanup ) { 12 if( at_cleanup ) { 13 *at_cleanup = [this]( cleanup_func_t && func, void* val ) { 14 push( std::move( func ), val ); 15 }; 16 } 17 } 10 guard_value_impl() = default; 18 11 19 12 ~guard_value_impl() { … … 40 33 }; 41 34 35 typedef std::function< void( cleanup_func_t, void * ) > at_cleanup_t; 42 36 43 37 class bool_ref { … … 62 56 // Deep magic (a.k.a template meta programming) to make the templated visitor work 63 57 // Basically the goal is to make 2 previsit_impl 64 // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of 58 // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of 65 59 // 'pass.previsit( node )' that compiles will be used for that node for that type 66 60 // This requires that this option only compile for passes that actually define an appropriate visit. -
src/Common/utility.h
r67fa9f9 r11dbfe1 305 305 // for ( val : group_iterate( container1, container2, ... ) ) {} 306 306 // syntax to have a for each that iterates multiple containers of the same length 307 // TODO: update to use variadic arguments , perfect forwarding307 // TODO: update to use variadic arguments 308 308 309 309 template< typename T1, typename T2 > -
src/ControlStruct/ExceptTranslate.cc
r67fa9f9 r11dbfe1 10 10 // Created On : Wed Jun 14 16:49:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Jun 30 13:30:00 201713 // Update Count : 112 // Last Modified On : Thr Jun 22 15:57:00 2017 13 // Update Count : 0 14 14 // 15 15 16 16 #include "ExceptTranslate.h" 17 17 #include "Common/PassVisitor.h" 18 #include "SynTree/Statement.h" 19 #include "SynTree/Declaration.h" 20 #include "SynTree/Expression.h" 21 #include "SynTree/Type.h" 22 #include "SynTree/Attribute.h" 23 24 namespace ControlStruct { 18 19 namespace ControlFlow { 25 20 26 21 // This (large) section could probably be moved out of the class … … 29 24 // Type(Qualifiers &, false, std::list<Attribute *> &) 30 25 31 // void (*function)() ;32 static FunctionType try_func_t(Type::Qualifiers(), false);26 // void (*function)() 27 static FunctionType void_func_t(Type::Qualifiers(), false); 33 28 // void (*function)(int, exception); 34 29 static FunctionType catch_func_t(Type::Qualifiers(), false); … … 37 32 // bool (*function)(exception); 38 33 static FunctionType handle_func_t(Type::Qualifiers(), false); 39 // void (*function)(__attribute__((unused)) void *);40 static FunctionType finally_func_t(Type::Qualifiers(), false);41 34 42 35 static void init_func_types() { 43 static boolinit_complete = false;36 static init_complete = false; 44 37 if (init_complete) { 45 38 return; 46 39 } 47 40 ObjectDecl index_obj( 48 " __handler_index",41 "index_t", 49 42 Type::StorageClasses(), 50 43 LinkageSpec::Cforall, 51 44 /*bitfieldWidth*/ NULL, 52 new BasicType( emptyQualifiers, BasicType::SignedInt),45 new BasicType(emptyQualifiers, BasicType::UnsignedInt), 53 46 /*init*/ NULL 54 );47 ); 55 48 ObjectDecl exception_obj( 56 " __exception_inst",49 "exception_t", 57 50 Type::StorageClasses(), 58 51 LinkageSpec::Cforall, 59 52 /*bitfieldWidth*/ NULL, 60 new PointerType( 61 emptyQualifiers, 62 new BasicType( emptyQualifiers, BasicType::SignedInt ) 63 ), 53 new BasicType(emptyQualifiers, BasicType::UnsignedInt), 64 54 /*init*/ NULL 65 );55 ); 66 56 ObjectDecl bool_obj( 67 " __ret_bool",57 "bool_t", 68 58 Type::StorageClasses(), 69 59 LinkageSpec::Cforall, … … 71 61 new BasicType(emptyQualifiers, BasicType::Bool), 72 62 /*init*/ NULL 73 ); 74 ObjectDecl voidptr_obj( 75 "__hook", 76 Type::StorageClasses(), 77 LinkageSpec::Cforall, 78 NULL, 79 new PointerType( 80 emptyQualifiers, 81 new VoidType( 82 emptyQualifiers 83 ), 84 std::list<Attribute *>{new Attribute("unused")} 85 ), 86 NULL 87 ); 88 89 catch_func_t.get_parameters().push_back( index_obj.clone() ); 90 catch_func_t.get_parameters().push_back( exception_obj.clone() ); 91 match_func_t.get_returnVals().push_back( index_obj.clone() ); 92 match_func_t.get_parameters().push_back( exception_obj.clone() ); 93 handle_func_t.get_returnVals().push_back( bool_obj.clone() ); 94 handle_func_t.get_parameters().push_back( exception_obj.clone() ); 95 finally_func_t.get_parameters().push_back( voidptr_obj.clone() ); 63 ); 64 65 catch_func_t.get_parameters().push_back(index_obj.clone()); 66 catch_func_t.get_parameters().push_back(exception_obj.clone()); 67 match_func_t.get_returnVals().push_back(index_obj.clone()); 68 match_func_t.get_parameters().push_back(exception_obj.clone()); 69 handle_func_t.get_returnVals().push_back(bool_obj.clone()); 70 handle_func_t.get_parameters().push_back(exception_obj.clone()); 96 71 97 72 init_complete = true; … … 103 78 104 79 void split( CatchList& allHandlers, CatchList& terHandlers, 105 CatchList& resHandlers ) {80 CatchList& resHandlers ) { 106 81 while ( !allHandlers.empty() ) { 107 CatchStmt * stmt = allHandlers.front();82 Statement * stmt = allHandlers.front(); 108 83 allHandlers.pop_front(); 109 if (Ca tchStmt::Terminate == stmt->get_kind()) {84 if (CaseStmt::Terminate == stmt->get_kind()) { 110 85 terHandlers.push_back(stmt); 111 86 } else { … … 117 92 template<typename T> 118 93 void free_all( std::list<T *> &list ) { 119 typenamestd::list<T *>::iterator it;94 std::list<T *>::iterator it; 120 95 for ( it = list.begin() ; it != list.end() ; ++it ) { 121 96 delete *it; … … 125 100 126 101 void appendDeclStmt( CompoundStmt * block, Declaration * item ) { 127 block->push_back(new DeclStmt(no Labels, item));128 } 129 130 Expression * nameOf( DeclarationWithType * decl) {131 return new VariableExpr( decl);102 block->push_back(new DeclStmt(no_labels, item)); 103 } 104 105 Expression * nameOf( FunctionDecl * function ) { 106 return new VariableExpr( function ); 132 107 } 133 108 134 109 // ThrowStmt Mutation Helpers 135 110 136 Statement * create_given_throw( 137 const char * throwFunc, ThrowStmt * throwStmt ) { 138 // { int NAME = EXPR; throwFunc( &NAME ); } 139 CompoundStmt * result = new CompoundStmt( noLabels ); 140 ObjectDecl * local = new ObjectDecl( 141 "__local_exception_copy", 142 Type::StorageClasses(), 143 LinkageSpec::Cforall, 144 NULL, 145 new BasicType( emptyQualifiers, BasicType::SignedInt ), 146 new SingleInit( throwStmt->get_expr() ) 147 ); 148 appendDeclStmt( result, local ); 149 UntypedExpr * call = new UntypedExpr( new NameExpr( throwFunc ) ); 150 call->get_args().push_back( new AddressExpr( nameOf( local ) ) ); 151 result->push_back( new ExprStmt( throwStmt->get_labels(), call ) ); 111 Statement * create_terminate_throw( ThrowStmt *throwStmt ) { 112 // __throw_terminate( EXPR ); 113 ApplicationExpr * call = new ApplicationExpr( /* ... */ ); 114 call->get_args.push_back( throwStmt->get_expr() ); 115 Statement * result = new ExprStmt( throwStmt->get_labels(), call ); 152 116 throwStmt->set_expr( nullptr ); 153 117 delete throwStmt; 154 118 return result; 155 119 } 156 157 Statement * create_terminate_throw( ThrowStmt *throwStmt ) {158 // { int NAME = EXPR; __throw_terminate( &NAME ); }159 return create_given_throw( "__cfaehm__throw_termination", throwStmt );160 }161 120 Statement * create_terminate_rethrow( ThrowStmt *throwStmt ) { 162 121 // __rethrow_terminate(); 163 assert( nullptr == throwStmt->get_expr() );164 122 Statement * result = new ExprStmt( 165 123 throwStmt->get_labels(), 166 new UntypedExpr( new NameExpr( "__cfaehm__rethrow_termination" ) )124 new ApplicationExpr( /* ... */ ); 167 125 ); 168 126 delete throwStmt; … … 171 129 Statement * create_resume_throw( ThrowStmt *throwStmt ) { 172 130 // __throw_resume( EXPR ); 173 return create_given_throw( "__cfaehm__throw_resumption", throwStmt ); 131 ApplicationExpr * call = new ApplicationExpr( /* ... */ ); 132 call->get_args.push_back( throwStmt->get_expr() ); 133 Statement * result = new ExprStmt( throwStmt->get_labels(), call ); 134 throwStmt->set_expr( nullptr ); 135 delete throwStmt; 136 return result; 174 137 } 175 138 Statement * create_resume_rethrow( ThrowStmt *throwStmt ) { … … 177 140 Statement * result = new ReturnStmt( 178 141 throwStmt->get_labels(), 179 new ConstantExpr( Constant::from_bool( false ) ) 142 new ConstantExpr( 143 Constant( 144 new BasicType( 145 Type::Qualifiers(), 146 BasicType::Bool 147 ), 148 "0") 149 ) 180 150 ); 181 151 delete throwStmt; … … 190 160 return block; 191 161 } 192 FunctionDecl * create_try_wrapper( CompoundStmt *body ) { 193 194 return new FunctionDecl( "try", Type::StorageClasses(), 195 LinkageSpec::Cforall, try_func_t.clone(), body ); 162 FunctionDecl * create_try_wrapper( TryStmt *tryStmt ) { 163 CompoundStmt * body = base_try->get_block(); 164 base_try->set_block(nullptr); 165 166 return new FunctionDecl("try", Type::StorageClasses(), 167 LinkageSpec::Cforall, void_func_t, body); 196 168 } 197 169 198 170 FunctionDecl * create_terminate_catch( CatchList &handlers ) { 199 171 std::list<CaseStmt *> handler_wrappers; 200 201 FunctionType *func_type = catch_func_t.clone();202 DeclarationWithType * index_obj = func_type->get_parameters().front();203 // DeclarationWithType * except_obj = func_type->get_parameters().back();204 172 205 173 // Index 1..{number of handlers} … … 210 178 CatchStmt * handler = *it; 211 179 212 // INTEGERconstant Version 213 // case `index`: 214 // { 215 // `handler.body` 216 // } 217 // return; 218 std::list<Statement *> caseBody; 219 caseBody.push_back( handler->get_body() ); 220 handler->set_body( nullptr ); 221 caseBody.push_back( new ReturnStmt( noLabels, nullptr ) ); 222 223 handler_wrappers.push_back( new CaseStmt( 180 std::list<Statement *> core; 181 if ( /*the exception is named*/ ) { 182 ObjectDecl * local_except = /* Dynamic case, same */; 183 core->push_back( new DeclStmt( noLabel, local_except ) ); 184 } 185 // Append the provided statement to the handler. 186 core->push_back( cur_handler->get_body() ); 187 // Append return onto the inner block? case stmt list? 188 CaseStmt * wrapper = new CaseStmt( 224 189 noLabels, 225 190 new ConstantExpr( Constant::from_int( index ) ), 226 caseBody 227 ) ); 191 core 192 ); 193 handler_wrappers.push_back(wrapper); 228 194 } 229 195 // TODO: Some sort of meaningful error on default perhaps? 230 231 std::list<Statement*> stmt_handlers;232 while ( !handler_wrappers.empty() ) {233 stmt_handlers.push_back( handler_wrappers.front() );234 handler_wrappers.pop_front();235 }236 196 237 197 SwitchStmt * handler_lookup = new SwitchStmt( 238 198 noLabels, 239 nameOf( index_obj ), 240 stmt_handlers 199 /*parameter 0: index*/, 200 handler_wrappers, 201 false 241 202 ); 242 203 CompoundStmt * body = new CompoundStmt( noLabels ); … … 244 205 245 206 return new FunctionDecl("catch", Type::StorageClasses(), 246 LinkageSpec::Cforall, func_type, body);207 LinkageSpec::Cforall, catch_func_t, body); 247 208 } 248 209 249 210 // Create a single check from a moddified handler. 250 // except_obj is referenced, modded_handler will be freed. 251 CompoundStmt *create_single_matcher( 252 DeclarationWithType * except_obj, CatchStmt * modded_handler ) { 253 CompoundStmt * block = new CompoundStmt( noLabels ); 254 255 // INTEGERconstant Version 256 assert( nullptr == modded_handler->get_decl() ); 257 ConstantExpr * number = 258 dynamic_cast<ConstantExpr*>( modded_handler->get_cond() ); 259 assert( number ); 260 modded_handler->set_cond( nullptr ); 261 262 Expression * cond; 263 { 264 std::list<Expression *> args; 265 args.push_back( number ); 266 267 std::list<Expression *> rhs_args; 268 rhs_args.push_back( nameOf( except_obj ) ); 269 Expression * rhs = new UntypedExpr( 270 new NameExpr( "*?" ), rhs_args ); 271 args.push_back( rhs ); 272 273 cond = new UntypedExpr( new NameExpr( "?==?" /*???*/), args ); 274 } 211 CompoundStmt *create_single_matcher( CatchStmt * modded_handler ) { 212 CompoundStmt * block = new CompoundStmt( noLables ); 213 214 appendDeclStmt( block, modded_handler->get_decl() ); 215 216 // TODO: This is not the actual check. 217 LogicalExpr * cond = new ConstantExpr( Constant::from_bool( false ) ); 275 218 276 219 if ( modded_handler->get_cond() ) { 277 cond = new LogicalExpr( cond, modded_handler->get_cond() ) ;220 cond = new LogicalExpr( cond, modded_handler->get_cond() )q 278 221 } 279 222 block->push_back( new IfStmt( noLabels, 280 cond, modded_handler->get_body() , nullptr ));223 cond, modded_handler->get_body() ); 281 224 282 225 modded_handler->set_decl( nullptr ); … … 289 232 FunctionDecl * create_terminate_match( CatchList &handlers ) { 290 233 CompoundStmt * body = new CompoundStmt( noLabels ); 291 292 FunctionType * func_type = match_func_t.clone();293 DeclarationWithType * except_obj = func_type->get_parameters().back();294 234 295 235 // Index 1..{number of handlers} … … 300 240 CatchStmt * handler = *it; 301 241 302 // Body should have been taken by create_terminate_catch. 303 assert( nullptr == handler->get_body() ); 304 305 // Create new body. 242 // body should have been taken by create_terminate_catch. 243 // assert( nullptr == handler->get_body() ); 306 244 handler->set_body( new ReturnStmt( noLabels, 307 245 new ConstantExpr( Constant::from_int( index ) ) ) ); 308 246 309 // Create the handler. 310 body->push_back( create_single_matcher( except_obj, handler ) ); 311 *it = nullptr; 312 } 313 314 body->push_back( new ReturnStmt( noLabels, new ConstantExpr( 315 Constant::from_int( 0 ) ) ) ); 247 body->push_back( create_single_matcher( handler ) ); 248 } 316 249 317 250 return new FunctionDecl("match", Type::StorageClasses(), 318 LinkageSpec::Cforall, func_type, body);319 } 320 321 CompoundStmt * create_terminate_caller(251 LinkageSpec::Cforall, match_func_t, body); 252 } 253 254 Statement * create_terminate_caller( 322 255 FunctionDecl * try_wrapper, 323 256 FunctionDecl * terminate_catch, 324 257 FunctionDecl * terminate_match) { 325 258 326 UntypedExpr * caller = new UntypedExpr( new NameExpr( 327 "__cfaehm__try_terminate" ) ); 328 std::list<Expression *>& args = caller->get_args(); 259 ApplicationExpr * caller = new ApplicationExpr( /* ... */ ); 260 std::list<Expression *>& args = caller.get_args(); 329 261 args.push_back( nameOf( try_wrapper ) ); 330 262 args.push_back( nameOf( terminate_catch ) ); 331 263 args.push_back( nameOf( terminate_match ) ); 332 264 333 CompoundStmt * callStmt = new CompoundStmt( noLabels ); 334 callStmt->push_back( new ExprStmt( noLabels, caller ) ); 335 return callStmt; 265 return new ExprStmt( noLabels, caller ); 336 266 } 337 267 338 268 FunctionDecl * create_resume_handler( CatchList &handlers ) { 339 CompoundStmt * body = new CompoundStmt( noLabels ); 340 341 FunctionType * func_type = match_func_t.clone(); 342 DeclarationWithType * except_obj = func_type->get_parameters().back(); 269 CompoundStmt * body = new CompountStmt( noLabels ); 343 270 344 271 CatchList::iterator it; … … 353 280 handling_code->push_back( handler->get_body() ); 354 281 } 355 handling_code->push_back( new ReturnStmt( noLabel s,282 handling_code->push_back( new ReturnStmt( noLabel, 356 283 new ConstantExpr( Constant::from_bool( false ) ) ) ); 357 284 handler->set_body( handling_code ); 358 285 359 286 // Create the handler. 360 body->push_back( create_single_matcher( except_obj, handler ) ); 361 *it = nullptr; 287 body->push_back( create_single_matcher( handler ) ); 362 288 } 363 289 364 290 return new FunctionDecl("handle", Type::StorageClasses(), 365 LinkageSpec::Cforall, func_type, body); 366 } 367 368 CompoundStmt * create_resume_wrapper( 369 StructDecl * node_decl, 291 LinkageSpec::Cforall, handle_func_t, body); 292 } 293 294 Statement * create_resume_wrapper( 370 295 Statement * wraps, 371 296 FunctionDecl * resume_handler ) { 372 297 CompoundStmt * body = new CompoundStmt( noLabels ); 373 298 374 // struct __try_resume_node __resume_node 375 // __attribute__((cleanup( __cfaehm__try_resume_cleanup ))); 376 // ** unwinding of the stack here could cause problems ** 377 // ** however I don't think that can happen currently ** 378 // __cfaehm__try_resume_setup( &__resume_node, resume_handler ); 299 // struct node = {current top resume handler, call to resume_handler}; 300 // __attribute__((cleanup( ... ))); 301 // set top resume handler to node. 302 // The wrapped statement. 303 304 ListInit * node_init; 305 { 306 std::list<Initializer*> field_inits; 307 field_inits.push_back( new SingleInit( /* ... */ ) ); 308 field_inits.push_back( new SingleInit( nameOf( resume_handler ) ) ); 309 node_init = new ListInit( field_inits ); 310 } 379 311 380 312 std::list< Attribute * > attributes; 381 313 { 382 314 std::list< Expression * > attr_params; 383 attr_params.push_back( n ew NameExpr(384 "__cfaehm__try_resume_cleanup") );385 attributes.push_back( new Attribute( "cleanup", attr_params ) );386 } 387 388 ObjectDecl * obj = newObjectDecl(389 " __resume_node",315 attr_params.push_back( nameOf( /* ... deconstructor ... */ ) ); 316 attrributes.push_back( new Attribute( "cleanup", attr_params ) ); 317 } 318 319 appendDeclStmt( body, 320 /**/ ObjectDecl( 321 "resume_node", 390 322 Type::StorageClasses(), 391 323 LinkageSpec::Cforall, 392 324 nullptr, 393 new StructInstType( 394 Type::Qualifiers(), 395 node_decl 396 ), 397 nullptr, 325 /* Type* = resume_node */, 326 node_init, 398 327 attributes 399 ); 400 appendDeclStmt( body, obj ); 401 402 UntypedExpr *setup = new UntypedExpr( new NameExpr( 403 "__cfaehm__try_resume_setup" ) ); 404 setup->get_args().push_back( new AddressExpr( nameOf( obj ) ) ); 405 setup->get_args().push_back( nameOf( resume_handler ) ); 406 407 body->push_back( new ExprStmt( noLabels, setup ) ); 408 328 ) 329 ); 409 330 body->push_back( wraps ); 410 331 return body; … … 412 333 413 334 FunctionDecl * create_finally_wrapper( TryStmt * tryStmt ) { 414 FinallyStmt * finally = tryStmt->get_finally(); 415 CompoundStmt * body = finally->get_block(); 416 finally->set_block( nullptr ); 417 delete finally; 335 CompoundStmt * body = tryStmt->get_finally(); 418 336 tryStmt->set_finally( nullptr ); 419 337 420 338 return new FunctionDecl("finally", Type::StorageClasses(), 421 LinkageSpec::Cforall, finally_func_t.clone(), body); 422 } 423 424 ObjectDecl * create_finally_hook( 425 StructDecl * hook_decl, FunctionDecl * finally_wrapper ) { 426 // struct __cfaehm__cleanup_hook __finally_hook 427 // __attribute__((cleanup( finally_wrapper ))); 339 LinkageSpec::Cforall, void_func_t, body); 340 } 341 342 ObjectDecl * create_finally_hook( FunctionDecl * finally_wrapper ) { 343 // struct _cleanup_hook NAME __attribute__((cleanup( ... ))); 428 344 429 345 // Make Cleanup Attribute. … … 432 348 std::list< Expression * > attr_params; 433 349 attr_params.push_back( nameOf( finally_wrapper ) ); 434 attr ibutes.push_back( new Attribute( "cleanup", attr_params ) );435 } 436 437 return new ObjectDecl(438 "__finally_hook",350 attrributes.push_back( new Attribute( "cleanup", attr_params ) ); 351 } 352 353 return ObjectDecl( /* ... */ 354 const std::string &name "finally_hook", 439 355 Type::StorageClasses(), 440 356 LinkageSpec::Cforall, 441 357 nullptr, 442 new StructInstType( 443 emptyQualifiers, 444 hook_decl 445 ), 358 /* ... Type * ... */, 446 359 nullptr, 447 360 attributes … … 450 363 451 364 452 class ExceptionMutatorCore : public With Guards{365 class ExceptionMutatorCore : public WithScoping { 453 366 enum Context { NoHandler, TerHandler, ResHandler }; 454 367 … … 457 370 // loop, switch or the goto stays within the function. 458 371 459 Context cur _context;372 Context curContext; 460 373 461 374 // We might not need this, but a unique base for each try block's … … 464 377 //unsigned int try_count = 0; 465 378 466 StructDecl *node_decl;467 StructDecl *hook_decl;468 379 469 380 public: 470 381 ExceptionMutatorCore() : 471 cur_context(NoHandler), 472 node_decl(nullptr), hook_decl(nullptr) 382 curContext(NoHandler) 473 383 {} 474 384 475 void premutate( CatchStmt *catchStmt ); 476 void premutate( StructDecl *structDecl ); 385 void premutate( CatchStmt *tryStmt ); 477 386 Statement * postmutate( ThrowStmt *throwStmt ); 478 387 Statement * postmutate( TryStmt *tryStmt ); … … 484 393 if ( throwStmt->get_expr() ) { 485 394 return create_terminate_throw( throwStmt ); 486 } else if ( TerHandler == cur _context ) {395 } else if ( TerHandler == curContext ) { 487 396 return create_terminate_rethrow( throwStmt ); 488 397 } else { 489 398 assertf(false, "Invalid throw in %s at %i\n", 490 throwStmt->location.filename .c_str(),399 throwStmt->location.filename, 491 400 throwStmt->location.linenumber); 492 401 return nullptr; … … 495 404 if ( throwStmt->get_expr() ) { 496 405 return create_resume_throw( throwStmt ); 497 } else if ( ResHandler == cur _context ) {406 } else if ( ResHandler == curContext ) { 498 407 return create_resume_rethrow( throwStmt ); 499 408 } else { 500 409 assertf(false, "Invalid throwResume in %s at %i\n", 501 throwStmt->location.filename .c_str(),410 throwStmt->location.filename, 502 411 throwStmt->location.linenumber); 503 412 return nullptr; … … 507 416 508 417 Statement * ExceptionMutatorCore::postmutate( TryStmt *tryStmt ) { 509 assert( node_decl );510 assert( hook_decl );511 512 418 // Generate a prefix for the function names? 513 419 514 CompoundStmt * block = new CompoundStmt( noLabels);515 CompoundStmt * inner = take_try_block( tryStmt );420 CompoundStmt * block = new CompoundStmt(); 421 Statement * inner = take_try_block( tryStmt ); 516 422 517 423 if ( tryStmt->get_finally() ) { … … 521 427 appendDeclStmt( block, finally_block ); 522 428 // Create and add the finally cleanup hook. 523 appendDeclStmt( block, 524 create_finally_hook( hook_decl, finally_block ) ); 525 } 526 527 CatchList termination_handlers; 528 CatchList resumption_handlers; 529 split( tryStmt->get_catchers(), 530 termination_handlers, resumption_handlers ); 531 532 if ( resumption_handlers.size() ) { 429 appendDeclStmt( block, create_finally_hook( finally_block ) ); 430 } 431 432 StatementList termination_handlers; 433 StatementList resumption_handlers; 434 split( tryStmt->get_handlers(), 435 termination_handlers, resumption_handlers ); 436 437 if ( resumeption_handlers.size() ) { 533 438 // Define the helper function. 534 439 FunctionDecl * resume_handler = … … 536 441 appendDeclStmt( block, resume_handler ); 537 442 // Prepare hooks 538 inner = create_resume_wrapper( node_decl,inner, resume_handler );443 inner = create_resume_wrapper( inner, resume_handler ); 539 444 } 540 445 … … 557 462 block->push_back( inner ); 558 463 559 //free_all( termination_handlers );560 //free_all( resumption_handlers );464 free_all( termination_handlers ); 465 free_all( resumption_handlers ); 561 466 562 467 return block; … … 564 469 565 470 void ExceptionMutatorCore::premutate( CatchStmt *catchStmt ) { 566 GuardValue( cur _context );567 if ( CatchStmt::Terminat e== catchStmt->get_kind() ) {568 cur _context = TerHandler;471 GuardValue( curContext ); 472 if ( CatchStmt::Termination == catchStmt->get_kind() ) { 473 curContext = TerHandler; 569 474 } else { 570 cur_context = ResHandler; 571 } 572 } 573 574 void ExceptionMutatorCore::premutate( StructDecl *structDecl ) { 575 if ( !structDecl->has_body() ) { 576 // Skip children? 577 return; 578 } else if ( structDecl->get_name() == "__cfaehm__try_resume_node" ) { 579 assert( nullptr == node_decl ); 580 node_decl = structDecl; 581 } else if ( structDecl->get_name() == "__cfaehm__cleanup_hook" ) { 582 assert( nullptr == hook_decl ); 583 hook_decl = structDecl; 584 } 585 // Later we might get the exception type as well. 586 } 587 588 void translateEHM( std::list< Declaration *> & translationUnit ) { 589 init_func_types(); 590 475 curContext = ResHandler; 476 } 477 } 478 479 void translateEHM( std::list< Declaration *> & translationUnit ) { 591 480 PassVisitor<ExceptionMutatorCore> translator; 592 481 for ( Declaration * decl : translationUnit ) { 593 decl-> acceptMutator( translator );482 decl->mutate( translator ); 594 483 } 595 484 } -
src/ControlStruct/ExceptTranslate.h
r67fa9f9 r11dbfe1 10 10 // Created On : Tus Jun 06 10:13:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Jun 30 10:20:00 201713 // Update Count : 212 // Last Modified On : Thr Jun 22 15:57:00 2017 13 // Update Count : 0 14 14 // 15 15 … … 17 17 #define EXCEPT_TRANSLATE_H 18 18 19 #include <list> 20 #include "SynTree/SynTree.h" 21 22 namespace ControlStruct { 19 namespace ControlFlow { 23 20 void translateEHM( std::list< Declaration *> & translationUnit ); 24 21 /* Converts exception handling structures into their underlying C code. -
src/ControlStruct/module.mk
r67fa9f9 r11dbfe1 10 10 ## Author : Richard C. Bilson 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 ## Last Modified By : Andrew Beach13 ## Last Modified On : Wed Jun 28 16:15:00 201714 ## Update Count : 412 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Thu Aug 4 11:38:06 2016 14 ## Update Count : 3 15 15 ############################################################################### 16 16 17 17 SRC += ControlStruct/LabelGenerator.cc \ 18 18 ControlStruct/LabelFixer.cc \ 19 ControlStruct/MLEMutator.cc \19 ControlStruct/MLEMutator.cc \ 20 20 ControlStruct/Mutate.cc \ 21 ControlStruct/ForExprMutator.cc \22 ControlStruct/ExceptTranslate.cc 21 ControlStruct/ForExprMutator.cc 22 -
src/GenPoly/Box.cc
r67fa9f9 r11dbfe1 504 504 DeclarationWithType *Pass1::mutate( FunctionDecl *functionDecl ) { 505 505 if ( functionDecl->get_statements() ) { // empty routine body ? 506 // std::cerr << "mutating function: " << functionDecl->get_mangleName() << std::endl;507 506 doBeginScope(); 508 507 scopeTyVars.beginScope(); … … 549 548 retval = oldRetval; 550 549 doEndScope(); 551 // std::cerr << "end function: " << functionDecl->get_mangleName() << std::endl;552 550 } // if 553 551 return functionDecl; … … 1118 1116 1119 1117 Expression *Pass1::mutate( ApplicationExpr *appExpr ) { 1120 // std::cerr << "mutate appExpr: " << InitTweak::getFunctionName( appExpr ) << std::endl;1118 // std::cerr << "mutate appExpr: "; 1121 1119 // for ( TyVarMap::iterator i = scopeTyVars.begin(); i != scopeTyVars.end(); ++i ) { 1122 1120 // std::cerr << i->first << " "; … … 1143 1141 ReferenceToType *dynRetType = isDynRet( function, exprTyVars ); 1144 1142 1145 // std::cerr << function << std::endl;1146 // std::cerr << "scopeTyVars: ";1147 // printTyVarMap( std::cerr, scopeTyVars );1148 // std::cerr << "exprTyVars: ";1149 // printTyVarMap( std::cerr, exprTyVars );1150 // std::cerr << "env: " << *env << std::endl;1151 // std::cerr << needsAdapter( function, scopeTyVars ) << ! needsAdapter( function, exprTyVars) << std::endl;1152 1153 1143 // NOTE: addDynRetParam needs to know the actual (generated) return type so it can make a temp variable, so pass the result type from the appExpr 1154 1144 // passTypeVars needs to know the program-text return type (i.e. the distinction between _conc_T30 and T3(int)) 1155 1145 // concRetType may not be a good name in one or both of these places. A more appropriate name change is welcome. 1156 1146 if ( dynRetType ) { 1157 // std::cerr << "dynRetType: " << dynRetType << std::endl;1158 1147 Type *concRetType = appExpr->get_result()->isVoid() ? nullptr : appExpr->get_result(); 1159 1148 ret = addDynRetParam( appExpr, concRetType, arg ); // xxx - used to use dynRetType instead of concRetType -
src/GenPoly/InstantiateGeneric.cc
r67fa9f9 r11dbfe1 22 22 #include "InstantiateGeneric.h" 23 23 24 #include "DeclMutator.h" 24 25 #include "GenPoly.h" 25 26 #include "ScopedSet.h" 26 27 #include "ScrubTyVars.h" 27 28 #include "Common/PassVisitor.h" 28 #include "PolyMutator.h" 29 30 #include "ResolvExpr/typeops.h" 31 32 #include "SynTree/Declaration.h" 33 #include "SynTree/Expression.h" 34 #include "SynTree/Type.h" 35 29 36 #include "Common/ScopedMap.h" 30 37 #include "Common/UniqueName.h" 31 38 #include "Common/utility.h" 32 33 #include "ResolvExpr/typeops.h"34 35 #include "SynTree/Declaration.h"36 #include "SynTree/Expression.h"37 #include "SynTree/Type.h"38 39 40 #include "InitTweak/InitTweak.h"41 42 39 43 40 namespace GenPoly { … … 156 153 } 157 154 155 // collect the environments of each TypeInstType so that type variables can be replaced 156 // xxx - possibly temporary solution. Access to type environments is required in GenericInstantiator, but it needs to be a DeclMutator which does not provide easy access to the type environments. 157 class EnvFinder final : public GenPoly::PolyMutator { 158 public: 159 using GenPoly::PolyMutator::mutate; 160 virtual Type * mutate( TypeInstType * inst ) override { 161 if ( env ) envMap[inst] = env; 162 return inst; 163 } 164 165 // don't want to associate an environment with TypeInstTypes that occur in function types - this may actually only apply to function types belonging to DeclarationWithTypes (or even just FunctionDecl)? 166 virtual Type * mutate( FunctionType * ftype ) override { 167 return ftype; 168 } 169 std::unordered_map< ReferenceToType *, TypeSubstitution * > envMap; 170 }; 171 158 172 /// Mutator pass that replaces concrete instantiations of generic types with actual struct declarations, scoped appropriately 159 struct GenericInstantiator final : public WithTypeSubstitution, public WithDeclsToAdd, public WithVisitorRef<GenericInstantiator>, public WithGuards{173 class GenericInstantiator final : public DeclMutator { 160 174 /// Map of (generic type, parameter list) pairs to concrete type instantiations 161 175 InstantiationMap< AggregateDecl, AggregateDecl > instantiations; … … 164 178 /// Namer for concrete types 165 179 UniqueName typeNamer; 166 /// Should not make use of type environment to replace types of function parameter and return values. 167 bool inFunctionType = false; 168 GenericInstantiator() : instantiations(), dtypeStatics(), typeNamer("_conc_") {} 169 170 Type* postmutate( StructInstType *inst ); 171 Type* postmutate( UnionInstType *inst ); 172 173 void premutate( FunctionType * ftype ) { 174 GuardValue( inFunctionType ); 175 inFunctionType = true; 176 } 177 178 void beginScope(); 179 void endScope(); 180 /// Reference to mapping of environments 181 const std::unordered_map< ReferenceToType *, TypeSubstitution * > & envMap; 182 public: 183 GenericInstantiator( const std::unordered_map< ReferenceToType *, TypeSubstitution * > & envMap ) : DeclMutator(), instantiations(), dtypeStatics(), typeNamer("_conc_"), envMap( envMap ) {} 184 185 using DeclMutator::mutate; 186 virtual Type* mutate( StructInstType *inst ) override; 187 virtual Type* mutate( UnionInstType *inst ) override; 188 189 virtual void doBeginScope() override; 190 virtual void doEndScope() override; 180 191 private: 181 192 /// Wrap instantiation lookup for structs … … 196 207 197 208 void instantiateGeneric( std::list< Declaration* > &translationUnit ) { 198 PassVisitor<GenericInstantiator> instantiator; 199 mutateAll( translationUnit, instantiator ); 209 EnvFinder finder; 210 mutateAll( translationUnit, finder ); 211 GenericInstantiator instantiator( finder.envMap ); 212 instantiator.mutateDeclarationList( translationUnit ); 200 213 } 201 214 … … 293 306 Type *GenericInstantiator::replaceWithConcrete( Type *type, bool doClone ) { 294 307 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) { 295 if ( env && ! inFunctionType ) { 308 if ( envMap.count( typeInst ) ) { 309 TypeSubstitution * env = envMap.at( typeInst ); 296 310 Type *concrete = env->lookup( typeInst->get_name() ); 297 311 if ( concrete ) { … … 317 331 318 332 319 Type* GenericInstantiator::postmutate( StructInstType *inst ) { 333 Type* GenericInstantiator::mutate( StructInstType *inst ) { 334 // mutate subtypes 335 Type *mutated = Mutator::mutate( inst ); 336 inst = dynamic_cast< StructInstType* >( mutated ); 337 if ( ! inst ) return mutated; 338 320 339 // exit early if no need for further mutation 321 340 if ( inst->get_parameters().empty() ) return inst; … … 349 368 substituteMembers( inst->get_baseStruct()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() ); 350 369 insert( inst, typeSubs, concDecl ); // must insert before recursion 351 concDecl->acceptMutator( * visitor); // recursively instantiate members352 declsToAddBefore.push_back( concDecl ); // must occur before declaration is added so that member instantiations appear first370 concDecl->acceptMutator( *this ); // recursively instantiate members 371 DeclMutator::addDeclaration( concDecl ); // must occur before declaration is added so that member instantiations appear first 353 372 } 354 373 StructInstType *newInst = new StructInstType( inst->get_qualifiers(), concDecl->get_name() ); … … 369 388 } 370 389 371 Type* GenericInstantiator::postmutate( UnionInstType *inst ) { 390 Type* GenericInstantiator::mutate( UnionInstType *inst ) { 391 // mutate subtypes 392 Type *mutated = Mutator::mutate( inst ); 393 inst = dynamic_cast< UnionInstType* >( mutated ); 394 if ( ! inst ) return mutated; 395 372 396 // exit early if no need for further mutation 373 397 if ( inst->get_parameters().empty() ) return inst; … … 399 423 substituteMembers( inst->get_baseUnion()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() ); 400 424 insert( inst, typeSubs, concDecl ); // must insert before recursion 401 concDecl->acceptMutator( * visitor); // recursively instantiate members402 declsToAddBefore.push_back( concDecl ); // must occur before declaration is added so that member instantiations appear first425 concDecl->acceptMutator( *this ); // recursively instantiate members 426 DeclMutator::addDeclaration( concDecl ); // must occur before declaration is added so that member instantiations appear first 403 427 } 404 428 UnionInstType *newInst = new UnionInstType( inst->get_qualifiers(), concDecl->get_name() ); … … 418 442 } 419 443 420 void GenericInstantiator::beginScope() { 444 void GenericInstantiator::doBeginScope() { 445 DeclMutator::doBeginScope(); 421 446 instantiations.beginScope(); 422 447 dtypeStatics.beginScope(); 423 448 } 424 449 425 void GenericInstantiator::endScope() { 450 void GenericInstantiator::doEndScope() { 451 DeclMutator::doEndScope(); 426 452 instantiations.endScope(); 427 453 dtypeStatics.endScope(); -
src/InitTweak/FixInit.cc
r67fa9f9 r11dbfe1 104 104 typedef AddStmtVisitor Parent; 105 105 using Parent::visit; 106 // use ordered data structure to maintain ordering for set_difference and for consistent error messages 107 typedef std::list< ObjectDecl * > ObjectSet; 106 typedef std::set< ObjectDecl * > ObjectSet; 108 107 virtual void visit( CompoundStmt *compoundStmt ) override; 109 108 virtual void visit( DeclStmt *stmt ) override; … … 117 116 118 117 // debug 119 template<typename ObjectSet>120 struct PrintSet {121 PrintSet( const ObjectSet & objs ) : objs( objs ) {}118 struct printSet { 119 typedef ObjDeclCollector::ObjectSet ObjectSet; 120 printSet( const ObjectSet & objs ) : objs( objs ) {} 122 121 const ObjectSet & objs; 123 122 }; 124 template<typename ObjectSet> 125 PrintSet<ObjectSet> printSet( const ObjectSet & objs ) { return PrintSet<ObjectSet>( objs ); } 126 template<typename ObjectSet> 127 std::ostream & operator<<( std::ostream & out, const PrintSet<ObjectSet> & set) { 123 std::ostream & operator<<( std::ostream & out, const printSet & set) { 128 124 out << "{ "; 129 125 for ( ObjectDecl * obj : set.objs ) { … … 728 724 // static bool __objName_uninitialized = true 729 725 BasicType * boolType = new BasicType( Type::Qualifiers(), BasicType::Bool ); 730 SingleInit * boolInitExpr = new SingleInit( new ConstantExpr( Constant::from_int( 1 ) ) );726 SingleInit * boolInitExpr = new SingleInit( new ConstantExpr( Constant::from_int( 1 ) ), noDesignators ); 731 727 ObjectDecl * isUninitializedVar = new ObjectDecl( objDecl->get_mangleName() + "_uninitialized", Type::StorageClasses( Type::Static ), LinkageSpec::Cforall, 0, boolType, boolInitExpr ); 732 728 isUninitializedVar->fixUniqueId(); … … 749 745 750 746 Statement * dtor = ctorInit->get_dtor(); 751 objDecl->set_init( nullptr);752 ctorInit->set_ctor( nullptr);747 objDecl->set_init( NULL ); 748 ctorInit->set_ctor( NULL ); 753 749 ctorInit->set_dtor( nullptr ); 754 750 if ( dtor ) { … … 803 799 } else { 804 800 stmtsToAddAfter.push_back( ctor ); 805 objDecl->set_init( nullptr);806 ctorInit->set_ctor( nullptr);801 objDecl->set_init( NULL ); 802 ctorInit->set_ctor( NULL ); 807 803 } 808 804 } // if 809 805 } else if ( Initializer * init = ctorInit->get_init() ) { 810 806 objDecl->set_init( init ); 811 ctorInit->set_init( nullptr);807 ctorInit->set_init( NULL ); 812 808 } else { 813 809 // no constructor and no initializer, which is okay 814 objDecl->set_init( nullptr);810 objDecl->set_init( NULL ); 815 811 } // if 816 812 delete ctorInit; … … 820 816 821 817 void ObjDeclCollector::visit( CompoundStmt * compoundStmt ) { 822 ObjectSetprevVars = curVars;818 std::set< ObjectDecl * > prevVars = curVars; 823 819 Parent::visit( compoundStmt ); 824 820 curVars = prevVars; … … 828 824 // keep track of all variables currently in scope 829 825 if ( ObjectDecl * objDecl = dynamic_cast< ObjectDecl * > ( stmt->get_decl() ) ) { 830 curVars. push_back( objDecl );826 curVars.insert( objDecl ); 831 827 } // if 832 828 Parent::visit( stmt ); … … 943 939 ) 944 940 if ( ! diff.empty() ) { 945 // create an auxilliary set for fast lookup -- can't make diff a set, because diff ordering should be consistent for error messages.946 std::unordered_set<ObjectDecl *> needsDestructor( diff.begin(), diff.end() );947 948 941 // go through decl ordered list of objectdecl. for each element that occurs in diff, output destructor 949 942 OrderedDecls ordered; 950 943 for ( OrderedDecls & rdo : reverseDeclOrder ) { 951 944 // add elements from reverseDeclOrder into ordered if they occur in diff - it is key that this happens in reverse declaration order. 952 copy_if( rdo.begin(), rdo.end(), back_inserter( ordered ), [&]( ObjectDecl * objDecl ) { return needsDestructor.count( objDecl ); } );945 copy_if( rdo.begin(), rdo.end(), back_inserter( ordered ), [&]( ObjectDecl * objDecl ) { return diff.count( objDecl ); } ); 953 946 } // for 954 947 insertDtors( ordered.begin(), ordered.end(), back_inserter( stmtsToAdd ) ); -
src/InitTweak/GenInit.cc
r67fa9f9 r11dbfe1 44 44 } 45 45 46 struct ReturnFixer : public WithStmtsToAdd, public WithGuards { 46 class ReturnFixer : public WithStmtsToAdd, public WithScopes { 47 public: 47 48 /// consistently allocates a temporary variable for the return value 48 49 /// of a function so that anything which the resolver decides can be constructed … … 58 59 }; 59 60 60 struct CtorDtor : public WithGuards, public WithShortCircuiting { 61 class CtorDtor final : public GenPoly::PolyMutator { 62 public: 63 typedef GenPoly::PolyMutator Parent; 64 using Parent::mutate; 61 65 /// create constructor and destructor statements for object declarations. 62 66 /// the actual call statements will be added in after the resolver has run … … 65 69 static void generateCtorDtor( std::list< Declaration * > &translationUnit ); 66 70 67 void previsit( ObjectDecl * ); 68 void previsit( FunctionDecl *functionDecl ); 69 71 virtual DeclarationWithType * mutate( ObjectDecl * ) override; 72 virtual DeclarationWithType * mutate( FunctionDecl *functionDecl ) override; 70 73 // should not traverse into any of these declarations to find objects 71 74 // that need to be constructed or destructed 72 v oid previsit( StructDecl *aggregateDecl );73 v oid previsit( UnionDecl *aggregateDecl ) { visit_children = false; }74 v oid previsit( EnumDecl *aggregateDecl ) { visit_children = false; }75 v oid previsit( TraitDecl *aggregateDecl ) { visit_children = false; }76 v oid previsit( TypeDecl *typeDecl ) { visit_children = false; }77 v oid previsit( TypedefDecl *typeDecl ) { visit_children = false; }78 79 v oid previsit( FunctionType *funcType ) { visit_children = false; }80 81 v oid previsit( CompoundStmt * compoundStmt );75 virtual Declaration* mutate( StructDecl *aggregateDecl ) override; 76 virtual Declaration* mutate( UnionDecl *aggregateDecl ) override { return aggregateDecl; } 77 virtual Declaration* mutate( EnumDecl *aggregateDecl ) override { return aggregateDecl; } 78 virtual Declaration* mutate( TraitDecl *aggregateDecl ) override { return aggregateDecl; } 79 virtual TypeDecl* mutate( TypeDecl *typeDecl ) override { return typeDecl; } 80 virtual Declaration* mutate( TypedefDecl *typeDecl ) override { return typeDecl; } 81 82 virtual Type * mutate( FunctionType *funcType ) override { return funcType; } 83 84 virtual CompoundStmt * mutate( CompoundStmt * compoundStmt ) override; 82 85 83 86 private: … … 208 211 209 212 void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) { 210 PassVisitor<CtorDtor>ctordtor;211 acceptAll( translationUnit, ctordtor );213 CtorDtor ctordtor; 214 mutateAll( translationUnit, ctordtor ); 212 215 } 213 216 … … 286 289 } 287 290 288 void CtorDtor::previsit( ObjectDecl * objDecl ) {291 DeclarationWithType * CtorDtor::mutate( ObjectDecl * objDecl ) { 289 292 handleDWT( objDecl ); 290 293 // hands off if @=, extern, builtin, etc. … … 298 301 objDecl->set_init( genCtorInit( objDecl ) ); 299 302 } 300 } 301 302 void CtorDtor::previsit( FunctionDecl *functionDecl ) { 303 GuardValue( inFunction ); 303 return Parent::mutate( objDecl ); 304 } 305 306 DeclarationWithType * CtorDtor::mutate( FunctionDecl *functionDecl ) { 307 ValueGuard< bool > oldInFunc = inFunction; 304 308 inFunction = true; 305 309 306 310 handleDWT( functionDecl ); 307 311 308 GuardScope( managedTypes);312 managedTypes.beginScope(); 309 313 // go through assertions and recursively add seen ctor/dtors 310 314 for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) { … … 313 317 } 314 318 } 315 316 PassVisitor<CtorDtor> newCtorDtor; 317 newCtorDtor.pass = *this; 318 maybeAccept( functionDecl->get_statements(), newCtorDtor ); 319 visit_children = false; // do not try and construct parameters or forall parameters - must happen after maybeAccept 320 } 321 322 void CtorDtor::previsit( StructDecl *aggregateDecl ) { 323 visit_children = false; // do not try to construct and destruct aggregate members 324 319 // parameters should not be constructed and destructed, so don't mutate FunctionType 320 functionDecl->set_statements( maybeMutate( functionDecl->get_statements(), *this ) ); 321 322 managedTypes.endScope(); 323 return functionDecl; 324 } 325 326 Declaration* CtorDtor::mutate( StructDecl *aggregateDecl ) { 325 327 // don't construct members, but need to take note if there is a managed member, 326 328 // because that means that this type is also managed … … 334 336 } 335 337 } 336 } 337 338 void CtorDtor::previsit( CompoundStmt * compoundStmt ) { 339 GuardScope( managedTypes ); 340 } 338 return aggregateDecl; 339 } 340 341 CompoundStmt * CtorDtor::mutate( CompoundStmt * compoundStmt ) { 342 managedTypes.beginScope(); 343 CompoundStmt * stmt = Parent::mutate( compoundStmt ); 344 managedTypes.endScope(); 345 return stmt; 346 } 347 341 348 } // namespace InitTweak 342 349 -
src/InitTweak/InitTweak.cc
r67fa9f9 r11dbfe1 14 14 public: 15 15 bool hasDesignations = false; 16 virtual void visit( Designation * des ) { 17 if ( ! des->get_designators().empty() ) hasDesignations = true; 18 else Visitor::visit( des ); 19 } 16 template<typename Init> 17 void handleInit( Init * init ) { 18 if ( ! init->get_designators().empty() ) hasDesignations = true; 19 else Visitor::visit( init ); 20 } 21 virtual void visit( SingleInit * singleInit ) { handleInit( singleInit); } 22 virtual void visit( ListInit * listInit ) { handleInit( listInit); } 20 23 }; 21 24 -
src/MakeLibCfa.cc
r67fa9f9 r11dbfe1 92 92 assert( ! objDecl->get_init() ); 93 93 std::list< Expression* > noDesignators; 94 objDecl->set_init( new SingleInit( new NameExpr( objDecl->get_name() ), false ) ); // cannot be constructed94 objDecl->set_init( new SingleInit( new NameExpr( objDecl->get_name() ), noDesignators, false ) ); // cannot be constructed 95 95 newDecls.push_back( objDecl ); 96 96 } -
src/Makefile.in
r67fa9f9 r11dbfe1 119 119 ControlStruct/driver_cfa_cpp-Mutate.$(OBJEXT) \ 120 120 ControlStruct/driver_cfa_cpp-ForExprMutator.$(OBJEXT) \ 121 ControlStruct/driver_cfa_cpp-ExceptTranslate.$(OBJEXT) \122 121 GenPoly/driver_cfa_cpp-Box.$(OBJEXT) \ 123 122 GenPoly/driver_cfa_cpp-GenPoly.$(OBJEXT) \ … … 162 161 ResolvExpr/driver_cfa_cpp-Occurs.$(OBJEXT) \ 163 162 ResolvExpr/driver_cfa_cpp-TypeEnvironment.$(OBJEXT) \ 164 ResolvExpr/driver_cfa_cpp-CurrentObject.$(OBJEXT) \165 163 SymTab/driver_cfa_cpp-Indexer.$(OBJEXT) \ 166 164 SymTab/driver_cfa_cpp-Mangler.$(OBJEXT) \ … … 396 394 ControlStruct/LabelGenerator.cc ControlStruct/LabelFixer.cc \ 397 395 ControlStruct/MLEMutator.cc ControlStruct/Mutate.cc \ 398 ControlStruct/ForExprMutator.cc \ 399 ControlStruct/ExceptTranslate.cc GenPoly/Box.cc \ 396 ControlStruct/ForExprMutator.cc GenPoly/Box.cc \ 400 397 GenPoly/GenPoly.cc GenPoly/PolyMutator.cc \ 401 398 GenPoly/ScrubTyVars.cc GenPoly/Lvalue.cc GenPoly/Specialize.cc \ … … 417 414 ResolvExpr/RenameVars.cc ResolvExpr/FindOpenVars.cc \ 418 415 ResolvExpr/PolyCost.cc ResolvExpr/Occurs.cc \ 419 ResolvExpr/TypeEnvironment.cc ResolvExpr/CurrentObject.cc \420 SymTab/ Indexer.cc SymTab/Mangler.cc SymTab/Validate.cc \421 SymTab/ FixFunction.cc SymTab/ImplementationType.cc \422 SymTab/ TypeEquality.cc SymTab/Autogen.cc SynTree/Type.cc \423 SynTree/ VoidType.cc SynTree/BasicType.cc \424 SynTree/ PointerType.cc SynTree/ArrayType.cc \425 SynTree/ FunctionType.cc SynTree/ReferenceToType.cc \426 SynTree/T upleType.cc SynTree/TypeofType.cc SynTree/AttrType.cc \416 ResolvExpr/TypeEnvironment.cc SymTab/Indexer.cc \ 417 SymTab/Mangler.cc SymTab/Validate.cc SymTab/FixFunction.cc \ 418 SymTab/ImplementationType.cc SymTab/TypeEquality.cc \ 419 SymTab/Autogen.cc SynTree/Type.cc SynTree/VoidType.cc \ 420 SynTree/BasicType.cc SynTree/PointerType.cc \ 421 SynTree/ArrayType.cc SynTree/FunctionType.cc \ 422 SynTree/ReferenceToType.cc SynTree/TupleType.cc \ 423 SynTree/TypeofType.cc SynTree/AttrType.cc \ 427 424 SynTree/VarArgsType.cc SynTree/ZeroOneType.cc \ 428 425 SynTree/Constant.cc SynTree/Expression.cc SynTree/TupleExpr.cc \ … … 595 592 ControlStruct/$(DEPDIR)/$(am__dirstamp) 596 593 ControlStruct/driver_cfa_cpp-ForExprMutator.$(OBJEXT): \ 597 ControlStruct/$(am__dirstamp) \598 ControlStruct/$(DEPDIR)/$(am__dirstamp)599 ControlStruct/driver_cfa_cpp-ExceptTranslate.$(OBJEXT): \600 594 ControlStruct/$(am__dirstamp) \ 601 595 ControlStruct/$(DEPDIR)/$(am__dirstamp) … … 727 721 ResolvExpr/$(am__dirstamp) \ 728 722 ResolvExpr/$(DEPDIR)/$(am__dirstamp) 729 ResolvExpr/driver_cfa_cpp-CurrentObject.$(OBJEXT): \730 ResolvExpr/$(am__dirstamp) \731 ResolvExpr/$(DEPDIR)/$(am__dirstamp)732 723 SymTab/$(am__dirstamp): 733 724 @$(MKDIR_P) SymTab … … 862 853 -rm -f Common/driver_cfa_cpp-UniqueName.$(OBJEXT) 863 854 -rm -f Concurrency/driver_cfa_cpp-Keywords.$(OBJEXT) 864 -rm -f ControlStruct/driver_cfa_cpp-ExceptTranslate.$(OBJEXT)865 855 -rm -f ControlStruct/driver_cfa_cpp-ForExprMutator.$(OBJEXT) 866 856 -rm -f ControlStruct/driver_cfa_cpp-LabelFixer.$(OBJEXT) … … 900 890 -rm -f ResolvExpr/driver_cfa_cpp-CommonType.$(OBJEXT) 901 891 -rm -f ResolvExpr/driver_cfa_cpp-ConversionCost.$(OBJEXT) 902 -rm -f ResolvExpr/driver_cfa_cpp-CurrentObject.$(OBJEXT)903 892 -rm -f ResolvExpr/driver_cfa_cpp-FindOpenVars.$(OBJEXT) 904 893 -rm -f ResolvExpr/driver_cfa_cpp-Occurs.$(OBJEXT) … … 976 965 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/driver_cfa_cpp-UniqueName.Po@am__quote@ 977 966 @AMDEP_TRUE@@am__include@ @am__quote@Concurrency/$(DEPDIR)/driver_cfa_cpp-Keywords.Po@am__quote@ 978 @AMDEP_TRUE@@am__include@ @am__quote@ControlStruct/$(DEPDIR)/driver_cfa_cpp-ExceptTranslate.Po@am__quote@979 967 @AMDEP_TRUE@@am__include@ @am__quote@ControlStruct/$(DEPDIR)/driver_cfa_cpp-ForExprMutator.Po@am__quote@ 980 968 @AMDEP_TRUE@@am__include@ @am__quote@ControlStruct/$(DEPDIR)/driver_cfa_cpp-LabelFixer.Po@am__quote@ … … 1014 1002 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/driver_cfa_cpp-CommonType.Po@am__quote@ 1015 1003 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/driver_cfa_cpp-ConversionCost.Po@am__quote@ 1016 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/driver_cfa_cpp-CurrentObject.Po@am__quote@1017 1004 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/driver_cfa_cpp-FindOpenVars.Po@am__quote@ 1018 1005 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/driver_cfa_cpp-Occurs.Po@am__quote@ … … 1368 1355 @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` 1369 1356 1370 ControlStruct/driver_cfa_cpp-ExceptTranslate.o: ControlStruct/ExceptTranslate.cc1371 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT ControlStruct/driver_cfa_cpp-ExceptTranslate.o -MD -MP -MF ControlStruct/$(DEPDIR)/driver_cfa_cpp-ExceptTranslate.Tpo -c -o ControlStruct/driver_cfa_cpp-ExceptTranslate.o `test -f 'ControlStruct/ExceptTranslate.cc' || echo '$(srcdir)/'`ControlStruct/ExceptTranslate.cc1372 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ControlStruct/$(DEPDIR)/driver_cfa_cpp-ExceptTranslate.Tpo ControlStruct/$(DEPDIR)/driver_cfa_cpp-ExceptTranslate.Po1373 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ControlStruct/ExceptTranslate.cc' object='ControlStruct/driver_cfa_cpp-ExceptTranslate.o' libtool=no @AMDEPBACKSLASH@1374 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@1375 @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-ExceptTranslate.o `test -f 'ControlStruct/ExceptTranslate.cc' || echo '$(srcdir)/'`ControlStruct/ExceptTranslate.cc1376 1377 ControlStruct/driver_cfa_cpp-ExceptTranslate.obj: ControlStruct/ExceptTranslate.cc1378 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT ControlStruct/driver_cfa_cpp-ExceptTranslate.obj -MD -MP -MF ControlStruct/$(DEPDIR)/driver_cfa_cpp-ExceptTranslate.Tpo -c -o ControlStruct/driver_cfa_cpp-ExceptTranslate.obj `if test -f 'ControlStruct/ExceptTranslate.cc'; then $(CYGPATH_W) 'ControlStruct/ExceptTranslate.cc'; else $(CYGPATH_W) '$(srcdir)/ControlStruct/ExceptTranslate.cc'; fi`1379 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ControlStruct/$(DEPDIR)/driver_cfa_cpp-ExceptTranslate.Tpo ControlStruct/$(DEPDIR)/driver_cfa_cpp-ExceptTranslate.Po1380 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ControlStruct/ExceptTranslate.cc' object='ControlStruct/driver_cfa_cpp-ExceptTranslate.obj' libtool=no @AMDEPBACKSLASH@1381 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@1382 @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-ExceptTranslate.obj `if test -f 'ControlStruct/ExceptTranslate.cc'; then $(CYGPATH_W) 'ControlStruct/ExceptTranslate.cc'; else $(CYGPATH_W) '$(srcdir)/ControlStruct/ExceptTranslate.cc'; fi`1383 1384 1357 GenPoly/driver_cfa_cpp-Box.o: GenPoly/Box.cc 1385 1358 @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 … … 1969 1942 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 1970 1943 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o ResolvExpr/driver_cfa_cpp-TypeEnvironment.obj `if test -f 'ResolvExpr/TypeEnvironment.cc'; then $(CYGPATH_W) 'ResolvExpr/TypeEnvironment.cc'; else $(CYGPATH_W) '$(srcdir)/ResolvExpr/TypeEnvironment.cc'; fi` 1971 1972 ResolvExpr/driver_cfa_cpp-CurrentObject.o: ResolvExpr/CurrentObject.cc1973 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT ResolvExpr/driver_cfa_cpp-CurrentObject.o -MD -MP -MF ResolvExpr/$(DEPDIR)/driver_cfa_cpp-CurrentObject.Tpo -c -o ResolvExpr/driver_cfa_cpp-CurrentObject.o `test -f 'ResolvExpr/CurrentObject.cc' || echo '$(srcdir)/'`ResolvExpr/CurrentObject.cc1974 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ResolvExpr/$(DEPDIR)/driver_cfa_cpp-CurrentObject.Tpo ResolvExpr/$(DEPDIR)/driver_cfa_cpp-CurrentObject.Po1975 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ResolvExpr/CurrentObject.cc' object='ResolvExpr/driver_cfa_cpp-CurrentObject.o' libtool=no @AMDEPBACKSLASH@1976 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@1977 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o ResolvExpr/driver_cfa_cpp-CurrentObject.o `test -f 'ResolvExpr/CurrentObject.cc' || echo '$(srcdir)/'`ResolvExpr/CurrentObject.cc1978 1979 ResolvExpr/driver_cfa_cpp-CurrentObject.obj: ResolvExpr/CurrentObject.cc1980 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT ResolvExpr/driver_cfa_cpp-CurrentObject.obj -MD -MP -MF ResolvExpr/$(DEPDIR)/driver_cfa_cpp-CurrentObject.Tpo -c -o ResolvExpr/driver_cfa_cpp-CurrentObject.obj `if test -f 'ResolvExpr/CurrentObject.cc'; then $(CYGPATH_W) 'ResolvExpr/CurrentObject.cc'; else $(CYGPATH_W) '$(srcdir)/ResolvExpr/CurrentObject.cc'; fi`1981 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ResolvExpr/$(DEPDIR)/driver_cfa_cpp-CurrentObject.Tpo ResolvExpr/$(DEPDIR)/driver_cfa_cpp-CurrentObject.Po1982 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ResolvExpr/CurrentObject.cc' object='ResolvExpr/driver_cfa_cpp-CurrentObject.obj' libtool=no @AMDEPBACKSLASH@1983 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@1984 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o ResolvExpr/driver_cfa_cpp-CurrentObject.obj `if test -f 'ResolvExpr/CurrentObject.cc'; then $(CYGPATH_W) 'ResolvExpr/CurrentObject.cc'; else $(CYGPATH_W) '$(srcdir)/ResolvExpr/CurrentObject.cc'; fi`1985 1944 1986 1945 SymTab/driver_cfa_cpp-Indexer.o: SymTab/Indexer.cc -
src/Parser/InitializerNode.cc
r67fa9f9 r11dbfe1 74 74 75 75 InitializerNode *moreInit; 76 if ( (moreInit = dynamic_cast< InitializerNode * >( get_next() ) ) ) {76 if ( get_next() != 0 && ((moreInit = dynamic_cast< InitializerNode * >( get_next() ) ) != 0) ) 77 77 moreInit->printOneLine( os ); 78 }79 78 } 80 79 81 80 Initializer *InitializerNode::build() const { 82 81 if ( aggregate ) { 83 // steal designators from children84 std::list< Designation * > designlist;85 InitializerNode * child = next_init();86 for ( ; child != nullptr; child = dynamic_cast< InitializerNode * >( child->get_next() ) ) {87 std::list< Expression * > desList;88 buildList< Expression, ExpressionNode >( child->designator, desList );89 designlist.push_back( new Designation( desList ) );90 } // for91 82 std::list< Initializer * > initlist; 92 83 buildList< Initializer, InitializerNode >( next_init(), initlist ); 84 85 std::list< Expression * > designlist; 86 87 if ( designator != 0 ) { 88 buildList< Expression, ExpressionNode >( designator, designlist ); 89 } // if 90 93 91 return new ListInit( initlist, designlist, maybeConstructed ); 94 92 } else { 95 if ( get_expression() != 0) { 96 return new SingleInit( maybeBuild< Expression >( get_expression() ), maybeConstructed ); 97 } 93 std::list< Expression * > designators; 94 95 if ( designator != 0 ) 96 buildList< Expression, ExpressionNode >( designator, designators ); 97 98 if ( get_expression() != 0) 99 return new SingleInit( maybeBuild< Expression >( get_expression() ), designators, maybeConstructed ); 98 100 } // if 101 99 102 return 0; 100 103 } -
src/Parser/TypeData.cc
r67fa9f9 r11dbfe1 760 760 if ( cur->has_enumeratorValue() ) { 761 761 ObjectDecl * member = dynamic_cast< ObjectDecl * >(* members); 762 member->set_init( new SingleInit( maybeMoveBuild< Expression >( cur->consume_enumeratorValue() ) ) );762 member->set_init( new SingleInit( maybeMoveBuild< Expression >( cur->consume_enumeratorValue() ), list< Expression * >() ) ); 763 763 } // if 764 764 } // for … … 777 777 TupleType * buildTuple( const TypeData * td ) { 778 778 assert( td->kind == TypeData::Tuple ); 779 std::list< Type * > types; 780 buildTypeList( td->tuple, types ); 781 TupleType * ret = new TupleType( buildQualifiers( td ), types ); 779 TupleType * ret = new TupleType( buildQualifiers( td ) ); 780 buildTypeList( td->tuple, ret->get_types() ); 782 781 buildForall( td->forall, ret->get_forall() ); 783 782 return ret; -
src/Parser/parser.yy
r67fa9f9 r11dbfe1 9 9 // Author : Peter A. Buhr 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 // Last Modified By : Andrew Beach12 // Last Modified On : Fri Jun 30 15:38:00201713 // Update Count : 241 511 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jun 28 22:11:22 2017 13 // Update Count : 2414 14 14 // 15 15 … … 104 104 std::string * str; 105 105 bool flag; 106 CatchStmt::Kind catch_kind;107 106 } 108 107 … … 193 192 %type<sn> switch_clause_list_opt switch_clause_list choose_clause_list_opt choose_clause_list 194 193 %type<sn> /* handler_list */ handler_clause finally_clause 195 %type<catch_kind> handler_key196 194 197 195 // declarations … … 960 958 handler_clause: 961 959 // TEMPORARY, TEST EXCEPTIONS 962 handler_key '(' push push INTEGERconstant pop ')' compound_statement pop 963 { $$ = new StatementNode( build_catch( $1, nullptr, new ExpressionNode( build_constantInteger( *$5 ) ), $8 ) ); } 964 | handler_clause handler_key '(' push push INTEGERconstant pop ')' compound_statement pop 965 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( $2, nullptr, new ExpressionNode( build_constantInteger( *$6 ) ), $9 ) ) ); } 966 967 | handler_key '(' push push exception_declaration pop ')' compound_statement pop 968 { $$ = new StatementNode( build_catch( $1, $5, nullptr, $8 ) ); } 969 | handler_clause handler_key '(' push push exception_declaration pop ')' compound_statement pop 970 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( $2, $6, nullptr, $9 ) ) ); } 971 ; 972 973 handler_key: 974 CATCH 975 { $$ = CatchStmt::Terminate; } 976 | CATCHRESUME 977 { $$ = CatchStmt::Resume; } 960 CATCH '(' push push INTEGERconstant pop ')' compound_statement pop 961 { $$ = new StatementNode( build_catch( CatchStmt::Terminate, nullptr, new ExpressionNode( build_constantInteger( *$5 ) ), $8 ) ); } 962 | handler_clause CATCH '(' push push INTEGERconstant pop ')' compound_statement pop 963 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( CatchStmt::Terminate, nullptr, new ExpressionNode( build_constantInteger( *$6 ) ), $9 ) ) ); } 964 965 | CATCH '(' push push exception_declaration pop ')' compound_statement pop 966 { $$ = new StatementNode( build_catch( CatchStmt::Terminate, $5, nullptr, $8 ) ); } 967 | handler_clause CATCH '(' push push exception_declaration pop ')' compound_statement pop 968 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( CatchStmt::Terminate, $6, nullptr, $9 ) ) ); } 969 | CATCHRESUME '(' push push exception_declaration pop ')' compound_statement pop 970 { $$ = new StatementNode( build_catch( CatchStmt::Resume, $5, nullptr, $8 ) ); } 971 | handler_clause CATCHRESUME '(' push push exception_declaration pop ')' compound_statement pop 972 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( CatchStmt::Resume, $6, nullptr, $9 ) ) ); } 978 973 ; 979 974 -
src/ResolvExpr/AlternativeFinder.cc
r67fa9f9 r11dbfe1 604 604 // ) 605 605 SymTab::Indexer decls( indexer ); 606 //PRINT(607 //std::cerr << "============= original indexer" << std::endl;608 //indexer.print( std::cerr );609 //std::cerr << "============= new indexer" << std::endl;610 //decls.print( std::cerr );611 //)606 PRINT( 607 std::cerr << "============= original indexer" << std::endl; 608 indexer.print( std::cerr ); 609 std::cerr << "============= new indexer" << std::endl; 610 decls.print( std::cerr ); 611 ) 612 612 addToIndexer( have, decls ); 613 613 AssertionSet newNeed; … … 809 809 } 810 810 811 Expression * restructureCast( Expression * argExpr, Type * toType ) {812 if ( argExpr->get_result()->size() > 1 && ! toType->isVoid() ) {813 // Argument expression is a tuple and the target type is not void. Cast each member of the tuple814 // to its corresponding target type, producing the tuple of those cast expressions. If there are815 // more components of the tuple than components in the target type, then excess components do not816 // come out in the result expression (but UniqueExprs ensure that side effects will still be done).817 if ( Tuples::maybeImpure( argExpr ) && ! dynamic_cast< UniqueExpr * >( argExpr ) ) {818 // expressions which may contain side effects require a single unique instance of the expression.819 argExpr = new UniqueExpr( argExpr );820 }821 std::list< Expression * > componentExprs;822 for ( unsigned int i = 0; i < toType->size(); i++ ) {823 // cast each component824 TupleIndexExpr * idx = new TupleIndexExpr( argExpr->clone(), i );825 componentExprs.push_back( restructureCast( idx, toType->getComponent( i ) ) );826 }827 delete argExpr;828 assert( componentExprs.size() > 0 );829 // produce the tuple of casts830 return new TupleExpr( componentExprs );831 } else {832 // handle normally833 return new CastExpr( argExpr, toType->clone() );834 }835 }836 837 811 void AlternativeFinder::visit( CastExpr *castExpr ) { 838 812 Type *& toType = castExpr->get_result(); … … 866 840 thisCost += Cost( 0, 0, discardedValues ); 867 841 868 candidates.push_back( Alternative( restructureCast( i->expr->clone(), toType ), i->env, i->cost, thisCost ) ); 842 Expression * argExpr = i->expr->clone(); 843 if ( argExpr->get_result()->size() > 1 && ! castExpr->get_result()->isVoid() ) { 844 // Argument expression is a tuple and the target type is not void. Cast each member of the tuple 845 // to its corresponding target type, producing the tuple of those cast expressions. If there are 846 // more components of the tuple than components in the target type, then excess components do not 847 // come out in the result expression (but UniqueExprs ensure that side effects will still be done). 848 if ( Tuples::maybeImpure( argExpr ) && ! dynamic_cast< UniqueExpr * >( argExpr ) ) { 849 // expressions which may contain side effects require a single unique instance of the expression. 850 argExpr = new UniqueExpr( argExpr ); 851 } 852 std::list< Expression * > componentExprs; 853 for ( unsigned int i = 0; i < castExpr->get_result()->size(); i++ ) { 854 // cast each component 855 TupleIndexExpr * idx = new TupleIndexExpr( argExpr->clone(), i ); 856 componentExprs.push_back( new CastExpr( idx, castExpr->get_result()->getComponent( i )->clone() ) ); 857 } 858 delete argExpr; 859 assert( componentExprs.size() > 0 ); 860 // produce the tuple of casts 861 candidates.push_back( Alternative( new TupleExpr( componentExprs ), i->env, i->cost, thisCost ) ); 862 } else { 863 // handle normally 864 candidates.push_back( Alternative( new CastExpr( argExpr->clone(), toType->clone() ), i->env, i->cost, thisCost ) ); 865 } 869 866 } // if 870 867 } // for … … 1185 1182 } 1186 1183 1187 void AlternativeFinder::visit( UntypedInitExpr *initExpr ) {1188 // handle each option like a cast1189 AltList candidates;1190 PRINT( std::cerr << "untyped init expr: " << initExpr << std::endl; )1191 // O(N^2) checks of d-types with e-types1192 for ( InitAlternative & initAlt : initExpr->get_initAlts() ) {1193 Type * toType = resolveTypeof( initAlt.type, indexer );1194 SymTab::validateType( toType, &indexer );1195 adjustExprType( toType, env, indexer );1196 // Ideally the call to findWithAdjustment could be moved out of the loop, but unfortunately it currently has to occur inside or else1197 // polymorphic return types are not properly bound to the initialization type, since return type variables are only open for the duration of resolving1198 // the UntypedExpr. This is only actually an issue in initialization contexts that allow more than one possible initialization type, but it is still suboptimal.1199 AlternativeFinder finder( indexer, env );1200 finder.targetType = toType;1201 finder.findWithAdjustment( initExpr->get_expr() );1202 for ( Alternative & alt : finder.get_alternatives() ) {1203 TypeEnvironment newEnv( alt.env );1204 AssertionSet needAssertions, haveAssertions;1205 OpenVarSet openVars; // find things in env that don't have a "representative type" and claim those are open vars?1206 PRINT( std::cerr << " @ " << toType << " " << initAlt.designation << std::endl; )1207 // It's possible that a cast can throw away some values in a multiply-valued expression. (An example is a1208 // cast-to-void, which casts from one value to zero.) Figure out the prefix of the subexpression results1209 // that are cast directly. The candidate is invalid if it has fewer results than there are types to cast1210 // to.1211 int discardedValues = alt.expr->get_result()->size() - toType->size();1212 if ( discardedValues < 0 ) continue;1213 // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not1214 // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))1215 // unification run for side-effects1216 unify( toType, alt.expr->get_result(), newEnv, needAssertions, haveAssertions, openVars, indexer ); // xxx - do some inspecting on this line... why isn't result bound to initAlt.type??1217 1218 Cost thisCost = castCost( alt.expr->get_result(), toType, indexer, newEnv );1219 if ( thisCost != Cost::infinity ) {1220 // count one safe conversion for each value that is thrown away1221 thisCost += Cost( 0, 0, discardedValues );1222 candidates.push_back( Alternative( new InitExpr( restructureCast( alt.expr->clone(), toType ), initAlt.designation->clone() ), newEnv, alt.cost, thisCost ) );1223 }1224 }1225 }1226 1227 // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the1228 // cvtCost member to the cost member (since the old cost is now irrelevant). Thus, calling findMinCost twice1229 // selects first based on argument cost, then on conversion cost.1230 AltList minArgCost;1231 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );1232 findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );1233 }1234 1184 } // namespace ResolvExpr 1235 1185 -
src/ResolvExpr/AlternativeFinder.h
r67fa9f9 r11dbfe1 73 73 virtual void visit( UniqueExpr *unqExpr ); 74 74 virtual void visit( StmtExpr *stmtExpr ); 75 virtual void visit( UntypedInitExpr *initExpr );76 75 /// Runs a new alternative finder on each element in [begin, end) 77 76 /// and writes each alternative finder to out. -
src/ResolvExpr/Resolver.cc
r67fa9f9 r11dbfe1 14 14 // 15 15 16 #include <iostream>17 16 #include "Resolver.h" 17 #include "AlternativeFinder.h" 18 18 #include "Alternative.h" 19 #include "AlternativeFinder.h"20 #include "CurrentObject.h"21 19 #include "RenameVars.h" 22 #include "Resolver.h"23 20 #include "ResolveTypeof.h" 24 21 #include "typeops.h" 25 22 #include "SynTree/Statement.h" 23 #include "SynTree/Type.h" 26 24 #include "SynTree/Expression.h" 27 25 #include "SynTree/Initializer.h" 28 #include "SynTree/Statement.h" 29 #include "SynTree/Type.h" 30 26 #include "SymTab/Indexer.h" 31 27 #include "SymTab/Autogen.h" 32 #include "SymTab/Indexer.h"33 34 28 #include "Common/utility.h" 35 36 29 #include "InitTweak/InitTweak.h" 37 30 31 #include <iostream> 38 32 using namespace std; 39 33 … … 45 39 if ( const Resolver * res = dynamic_cast< const Resolver * >( &other ) ) { 46 40 functionReturn = res->functionReturn; 47 currentObject = res->currentObject;41 initContext = res->initContext; 48 42 inEnumDecl = res->inEnumDecl; 49 43 } … … 70 64 virtual void visit( BranchStmt *branchStmt ) override; 71 65 virtual void visit( ReturnStmt *returnStmt ) override; 72 virtual void visit( ThrowStmt *throwStmt ) override;73 66 74 67 virtual void visit( SingleInit *singleInit ) override; … … 86 79 87 80 Type * functionReturn = nullptr; 88 CurrentObject currentObject = nullptr;81 Type *initContext = nullptr; 89 82 bool inEnumDecl = false; 90 83 }; … … 193 186 // each value of initContext is retained, so the type on the first analysis is preserved and used for selecting 194 187 // the RHS. 195 ValueGuard<CurrentObject> temp( currentObject );196 currentObject = CurrentObject( objectDecl->get_type() );197 if ( inEnumDecl && dynamic_cast< EnumInstType * >( objectDecl->get_type()) ) {188 Type *temp = initContext; 189 initContext = new_type; 190 if ( inEnumDecl && dynamic_cast< EnumInstType * >( initContext ) ) { 198 191 // enumerator initializers should not use the enum type to initialize, since 199 192 // the enum type is still incomplete at this point. Use signed int instead. 200 currentObject = CurrentObject( new BasicType( Type::Qualifiers(), BasicType::SignedInt ));193 initContext = new BasicType( Type::Qualifiers(), BasicType::SignedInt ); 201 194 } 202 195 Parent::visit( objectDecl ); 203 if ( inEnumDecl && dynamic_cast< EnumInstType * >( objectDecl->get_type()) ) {196 if ( inEnumDecl && dynamic_cast< EnumInstType * >( initContext ) ) { 204 197 // delete newly created signed int type 205 // delete currentObject.getType(); 206 } 198 delete initContext; 199 } 200 initContext = temp; 207 201 } 208 202 … … 321 315 322 316 void Resolver::visit( SwitchStmt *switchStmt ) { 323 ValueGuard< CurrentObject > oldCurrentObject( currentObject );317 ValueGuard< Type * > oldInitContext( initContext ); 324 318 Expression *newExpr; 325 319 newExpr = findIntegralExpression( switchStmt->get_condition(), *this ); … … 327 321 switchStmt->set_condition( newExpr ); 328 322 329 currentObject = CurrentObject( newExpr->get_result());323 initContext = newExpr->get_result(); 330 324 Parent::visit( switchStmt ); 331 325 } … … 333 327 void Resolver::visit( CaseStmt *caseStmt ) { 334 328 if ( caseStmt->get_condition() ) { 335 std::list< InitAlternative > initAlts = currentObject.getOptions(); 336 assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral expression." ); 337 CastExpr * castExpr = new CastExpr( caseStmt->get_condition(), initAlts.front().type->clone() ); 329 assert( initContext ); 330 CastExpr * castExpr = new CastExpr( caseStmt->get_condition(), initContext->clone() ); 338 331 Expression * newExpr = findSingleExpression( castExpr, *this ); 339 332 castExpr = safe_dynamic_cast< CastExpr * >( newExpr ); … … 367 360 } 368 361 369 void Resolver::visit( ThrowStmt *throwStmt ) {370 if ( throwStmt->get_expr() ) {371 Expression * wrapped = new CastExpr( throwStmt->get_expr(), new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );372 Expression * newExpr = findSingleExpression( wrapped, *this );373 throwStmt->set_expr( newExpr );374 }375 }376 377 362 template< typename T > 378 363 bool isCharType( T t ) { … … 385 370 386 371 void Resolver::visit( SingleInit *singleInit ) { 387 // resolve initialization using the possibilities as determined by the currentObject cursor 388 UntypedInitExpr * untyped = new UntypedInitExpr( singleInit->get_value(), currentObject.getOptions() ); 389 Expression * newExpr = findSingleExpression( untyped, *this ); 390 InitExpr * initExpr = safe_dynamic_cast< InitExpr * >( newExpr ); 391 392 // move cursor to the object that is actually initialized 393 currentObject.setNext( initExpr->get_designation() ); 394 395 // discard InitExpr wrapper and retain relevant pieces 396 newExpr = initExpr->get_expr(); 397 newExpr->set_env( initExpr->get_env() ); 398 initExpr->set_expr( nullptr ); 399 initExpr->set_env( nullptr ); 400 delete initExpr; 401 402 // get the actual object's type (may not exactly match what comes back from the resolver due to conversions) 403 Type * initContext = currentObject.getCurrentType(); 404 405 // check if actual object's type is char[] 406 if ( ArrayType * at = dynamic_cast< ArrayType * >( initContext ) ) { 407 if ( isCharType( at->get_base() ) ) { 408 // check if the resolved type is char * 409 if ( PointerType * pt = dynamic_cast< PointerType *>( newExpr->get_result() ) ) { 410 if ( isCharType( pt->get_base() ) ) { 411 // strip cast if we're initializing a char[] with a char *, e.g. char x[] = "hello"; 412 CastExpr *ce = safe_dynamic_cast< CastExpr * >( newExpr ); 413 newExpr = ce->get_arg(); 414 ce->set_arg( nullptr ); 415 delete ce; 372 if ( singleInit->get_value() ) { 373 // // find all the d's 374 // std::list<Expression *> &designators = singleInit->get_designators(); 375 // std::list<Type *> types1{ initContext }, types2; 376 // for ( Expression * expr: designators ) { 377 // cerr << expr << endl; 378 // if ( NameExpr * nexpr = dynamic_cast<NameExpr *>( expr ) ) { 379 // for ( Type * type: types1 ) { 380 // cerr << type << endl; 381 // ReferenceToType * fred = dynamic_cast<ReferenceToType *>(type); 382 // std::list<Declaration *> members; 383 // if ( fred ) { 384 // fred->lookup( nexpr->get_name(), members ); // concatenate identical field name 385 // for ( Declaration * mem: members ) { 386 // if ( DeclarationWithType * dwt = dynamic_cast<DeclarationWithType *>(mem) ) { 387 // types2.push_back( dwt->get_type() ); 388 // } // if 389 // } // for 390 // } // if 391 // } // for 392 // types1 = types2; 393 // types2.clear(); 394 // } // if 395 // } // for 396 // // for ( Type * type: types1 ) { 397 // // cerr << type << endl; 398 // // } // for 399 400 // // O(N^2) checks of d-types with f-types 401 // // find the minimum cost 402 CastExpr *castExpr = new CastExpr( singleInit->get_value(), initContext->clone() ); 403 Expression *newExpr = findSingleExpression( castExpr, *this ); 404 delete castExpr; 405 singleInit->set_value( newExpr ); 406 407 // check if initializing type is char[] 408 if ( ArrayType * at = dynamic_cast< ArrayType * >( initContext ) ) { 409 if ( isCharType( at->get_base() ) ) { 410 // check if the resolved type is char * 411 if ( PointerType * pt = dynamic_cast< PointerType *>( newExpr->get_result() ) ) { 412 if ( isCharType( pt->get_base() ) ) { 413 // strip cast if we're initializing a char[] with a char *, e.g. char x[] = "hello"; 414 CastExpr *ce = dynamic_cast< CastExpr * >( newExpr ); 415 singleInit->set_value( ce->get_arg() ); 416 ce->set_arg( NULL ); 417 delete ce; 418 } 416 419 } 417 420 } 418 421 } 419 } 420 421 // set initializer expr to resolved express 422 singleInit->set_value( newExpr ); 423 424 // move cursor to next object in preparation for next initializer 425 currentObject.increment(); 422 } // if 423 } 424 425 template< typename AggrInst > 426 TypeSubstitution makeGenericSubstitutuion( AggrInst * inst ) { 427 assert( inst ); 428 assert( inst->get_baseParameters() ); 429 std::list< TypeDecl * > baseParams = *inst->get_baseParameters(); 430 std::list< Expression * > typeSubs = inst->get_parameters(); 431 TypeSubstitution subs( baseParams.begin(), baseParams.end(), typeSubs.begin() ); 432 return subs; 433 } 434 435 ReferenceToType * isStructOrUnion( Type * type ) { 436 if ( StructInstType * sit = dynamic_cast< StructInstType * >( type ) ) { 437 return sit; 438 } else if ( UnionInstType * uit = dynamic_cast< UnionInstType * >( type ) ) { 439 return uit; 440 } 441 return nullptr; 442 } 443 444 void Resolver::resolveSingleAggrInit( Declaration * dcl, InitIterator & init, InitIterator & initEnd, TypeSubstitution sub ) { 445 DeclarationWithType * dt = dynamic_cast< DeclarationWithType * >( dcl ); 446 assert( dt ); 447 // need to substitute for generic types, so that casts are to concrete types 448 initContext = dt->get_type()->clone(); 449 sub.apply( initContext ); 450 451 try { 452 if ( init == initEnd ) return; // stop when there are no more initializers 453 (*init)->accept( *this ); 454 ++init; // made it past an initializer 455 } catch( SemanticError & ) { 456 // need to delve deeper, if you can 457 if ( ReferenceToType * type = isStructOrUnion( initContext ) ) { 458 resolveAggrInit( type, init, initEnd ); 459 } else { 460 // member is not an aggregate type, so can't go any deeper 461 462 // might need to rethink what is being thrown 463 throw; 464 } // if 465 } 466 } 467 468 void Resolver::resolveAggrInit( ReferenceToType * inst, InitIterator & init, InitIterator & initEnd ) { 469 if ( StructInstType * sit = dynamic_cast< StructInstType * >( inst ) ) { 470 TypeSubstitution sub = makeGenericSubstitutuion( sit ); 471 StructDecl * st = sit->get_baseStruct(); 472 if(st->get_members().empty()) return; 473 // want to resolve each initializer to the members of the struct, 474 // but if there are more initializers than members we should stop 475 list< Declaration * >::iterator it = st->get_members().begin(); 476 for ( ; it != st->get_members().end(); ++it) { 477 resolveSingleAggrInit( *it, init, initEnd, sub ); 478 } 479 } else if ( UnionInstType * uit = dynamic_cast< UnionInstType * >( inst ) ) { 480 TypeSubstitution sub = makeGenericSubstitutuion( uit ); 481 UnionDecl * un = uit->get_baseUnion(); 482 if(un->get_members().empty()) return; 483 // only resolve to the first member of a union 484 resolveSingleAggrInit( *un->get_members().begin(), init, initEnd, sub ); 485 } // if 426 486 } 427 487 428 488 void Resolver::visit( ListInit * listInit ) { 429 // move cursor into brace-enclosed initializer-list 430 currentObject.enterListInit(); 431 // xxx - fix this so that the list isn't copied, iterator should be used to change current element 432 std::list<Designation *> newDesignations; 433 for ( auto p : group_iterate(listInit->get_designations(), listInit->get_initializers()) ) { 434 // iterate designations and initializers in pairs, moving the cursor to the current designated object and resolving 435 // the initializer against that object. 436 Designation * des = std::get<0>(p); 437 Initializer * init = std::get<1>(p); 438 newDesignations.push_back( currentObject.findNext( des ) ); 439 init->accept( *this ); 440 } 441 // set the set of 'resolved' designations and leave the brace-enclosed initializer-list 442 listInit->get_designations() = newDesignations; // xxx - memory management 443 currentObject.exitListInit(); 444 445 // xxx - this part has not be folded into CurrentObject yet 446 // } else if ( TypeInstType * tt = dynamic_cast< TypeInstType * >( initContext ) ) { 447 // Type * base = tt->get_baseType()->get_base(); 448 // if ( base ) { 449 // // know the implementation type, so try using that as the initContext 450 // ObjectDecl tmpObj( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, base->clone(), nullptr ); 451 // currentObject = &tmpObj; 452 // visit( listInit ); 453 // } else { 454 // // missing implementation type -- might be an unknown type variable, so try proceeding with the current init context 455 // Parent::visit( listInit ); 456 // } 457 // } else { 489 InitIterator iter = listInit->begin(); 490 InitIterator end = listInit->end(); 491 492 if ( ArrayType * at = dynamic_cast< ArrayType * >( initContext ) ) { 493 // resolve each member to the base type of the array 494 for ( ; iter != end; ++iter ) { 495 initContext = at->get_base(); 496 (*iter)->accept( *this ); 497 } // for 498 } else if ( TupleType * tt = dynamic_cast< TupleType * > ( initContext ) ) { 499 for ( Type * t : *tt ) { 500 if ( iter == end ) break; 501 initContext = t; 502 (*iter++)->accept( *this ); 503 } 504 } else if ( ReferenceToType * type = isStructOrUnion( initContext ) ) { 505 resolveAggrInit( type, iter, end ); 506 } else if ( TypeInstType * tt = dynamic_cast< TypeInstType * >( initContext ) ) { 507 Type * base = tt->get_baseType()->get_base(); 508 if ( base ) { 509 // know the implementation type, so try using that as the initContext 510 initContext = base; 511 visit( listInit ); 512 } else { 513 // missing implementation type -- might be an unknown type variable, so try proceeding with the current init context 514 Parent::visit( listInit ); 515 } 516 } else { 517 assert( dynamic_cast< BasicType * >( initContext ) || dynamic_cast< PointerType * >( initContext ) 518 || dynamic_cast< ZeroType * >( initContext ) || dynamic_cast< OneType * >( initContext ) || dynamic_cast < EnumInstType * > ( initContext ) ); 519 // basic types are handled here 520 Parent::visit( listInit ); 521 } 522 523 #if 0 524 if ( ArrayType *at = dynamic_cast<ArrayType*>(initContext) ) { 525 std::list<Initializer *>::iterator iter( listInit->begin_initializers() ); 526 for ( ; iter != listInit->end_initializers(); ++iter ) { 527 initContext = at->get_base(); 528 (*iter)->accept( *this ); 529 } // for 530 } else if ( StructInstType *st = dynamic_cast<StructInstType*>(initContext) ) { 531 StructDecl *baseStruct = st->get_baseStruct(); 532 std::list<Declaration *>::iterator iter1( baseStruct->get_members().begin() ); 533 std::list<Initializer *>::iterator iter2( listInit->begin_initializers() ); 534 for ( ; iter1 != baseStruct->get_members().end() && iter2 != listInit->end_initializers(); ++iter2 ) { 535 if ( (*iter2)->get_designators().empty() ) { 536 DeclarationWithType *dt = dynamic_cast<DeclarationWithType *>( *iter1 ); 537 initContext = dt->get_type(); 538 (*iter2)->accept( *this ); 539 ++iter1; 540 } else { 541 StructDecl *st = baseStruct; 542 iter1 = st->get_members().begin(); 543 std::list<Expression *>::iterator iter3( (*iter2)->get_designators().begin() ); 544 for ( ; iter3 != (*iter2)->get_designators().end(); ++iter3 ) { 545 NameExpr *key = dynamic_cast<NameExpr *>( *iter3 ); 546 assert( key ); 547 for ( ; iter1 != st->get_members().end(); ++iter1 ) { 548 if ( key->get_name() == (*iter1)->get_name() ) { 549 (*iter1)->print( cout ); 550 cout << key->get_name() << endl; 551 ObjectDecl *fred = dynamic_cast<ObjectDecl *>( *iter1 ); 552 assert( fred ); 553 StructInstType *mary = dynamic_cast<StructInstType*>( fred->get_type() ); 554 assert( mary ); 555 st = mary->get_baseStruct(); 556 iter1 = st->get_members().begin(); 557 break; 558 } // if 559 } // for 560 } // for 561 ObjectDecl *fred = dynamic_cast<ObjectDecl *>( *iter1 ); 562 assert( fred ); 563 initContext = fred->get_type(); 564 (*listInit->begin_initializers())->accept( *this ); 565 } // if 566 } // for 567 } else if ( UnionInstType *st = dynamic_cast<UnionInstType*>(initContext) ) { 568 DeclarationWithType *dt = dynamic_cast<DeclarationWithType *>( *st->get_baseUnion()->get_members().begin() ); 569 initContext = dt->get_type(); 570 (*listInit->begin_initializers())->accept( *this ); 571 } // if 572 #endif 458 573 } 459 574 -
src/ResolvExpr/Unify.cc
r67fa9f9 r11dbfe1 606 606 } else if ( tupleParam ) { 607 607 // bundle other parameters into tuple to match 608 std::list< Type * > binderTypes;608 TupleType* binder = new TupleType{ paramTy->get_qualifiers() }; 609 609 610 610 do { 611 binder Types.push_back( otherParam->get_type()->clone() );611 binder->get_types().push_back( otherParam->get_type()->clone() ); 612 612 ++jt; 613 613 … … 618 618 } while (true); 619 619 620 otherParamTy = new TupleType{ paramTy->get_qualifiers(), binderTypes };620 otherParamTy = binder; 621 621 ++it; // skip ttype parameter for break 622 622 } else if ( otherTupleParam ) { 623 623 // bundle parameters into tuple to match other 624 std::list< Type * > binderTypes;624 TupleType* binder = new TupleType{ otherParamTy->get_qualifiers() }; 625 625 626 626 do { 627 binder Types.push_back( param->get_type()->clone() );627 binder->get_types().push_back( param->get_type()->clone() ); 628 628 ++it; 629 629 … … 634 634 } while (true); 635 635 636 paramTy = new TupleType{ otherParamTy->get_qualifiers(), binderTypes };636 paramTy = binder; 637 637 ++jt; // skip ttype parameter for break 638 638 } … … 756 756 return function->get_returnVals().front()->get_type()->clone(); 757 757 } else { 758 std::list< Type * > types;758 TupleType * tupleType = new TupleType( Type::Qualifiers() ); 759 759 for ( DeclarationWithType * decl : function->get_returnVals() ) { 760 t ypes.push_back( decl->get_type()->clone() );760 tupleType->get_types().push_back( decl->get_type()->clone() ); 761 761 } // for 762 return new TupleType( Type::Qualifiers(), types );762 return tupleType; 763 763 } 764 764 } -
src/ResolvExpr/module.mk
r67fa9f9 r11dbfe1 6 6 ## file "LICENCE" distributed with Cforall. 7 7 ## 8 ## module.mk -- 8 ## module.mk -- 9 9 ## 10 10 ## Author : Richard C. Bilson … … 31 31 ResolvExpr/PolyCost.cc \ 32 32 ResolvExpr/Occurs.cc \ 33 ResolvExpr/TypeEnvironment.cc \ 34 ResolvExpr/CurrentObject.cc 33 ResolvExpr/TypeEnvironment.cc -
src/SymTab/Autogen.h
r67fa9f9 r11dbfe1 25 25 26 26 namespace SymTab { 27 /// Generates assignment operators, constructors, and destructor for aggregate types as required28 void autogenerateRoutines( std::list< Declaration * > &translationUnit );27 /// Generates assignment operators, constructors, and destructor for aggregate types as required 28 void autogenerateRoutines( std::list< Declaration * > &translationUnit ); 29 29 30 /// returns true if obj's name is the empty string and it has a bitfield width31 bool isUnnamedBitfield( ObjectDecl * obj );30 /// returns true if obj's name is the empty string and it has a bitfield width 31 bool isUnnamedBitfield( ObjectDecl * obj ); 32 32 33 /// size_t type - set when size_t typedef is seen. Useful in a few places,34 /// such as in determining array dimension type35 extern Type * SizeType;33 /// size_t type - set when size_t typedef is seen. Useful in a few places, 34 /// such as in determining array dimension type 35 extern Type * SizeType; 36 36 37 /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls.38 template< typename OutputIterator >37 /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls. 38 template< typename OutputIterator > 39 39 Statement * genCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, bool addCast = false, bool forward = true ); 40 40 41 /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types.42 /// optionally returns a statement which must be inserted prior to the containing loop, if there is one43 template< typename OutputIterator >41 /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types. 42 /// optionally returns a statement which must be inserted prior to the containing loop, if there is one 43 template< typename OutputIterator > 44 44 Statement * genScalarCall( InitTweak::InitExpander & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, Type * type, bool addCast = false ) { 45 45 // want to be able to generate assignment, ctor, and dtor generically, … … 50 50 dstParam = new AddressExpr( dstParam ); 51 51 if ( addCast ) { 52 // cast to T* with qualifiers removed, so that qualified objects can be constructed 53 // and destructed with the same functions as non-qualified objects. 54 // unfortunately, lvalue is considered a qualifier. For AddressExpr to resolve, its argument 55 // must have an lvalue qualified type, so remove all qualifiers except lvalue. If we ever 56 // remove lvalue as a qualifier, this can change to 57 // type->get_qualifiers() = Type::Qualifiers(); 58 assert( type ); 59 Type * castType = type->clone(); 60 castType->get_qualifiers() -= Type::Qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic ); 61 castType->set_lvalue( true ); // xxx - might not need this 62 dstParam = new CastExpr( dstParam, new PointerType( Type::Qualifiers(), castType ) ); 52 // cast to T* with qualifiers removed, so that qualified objects can be constructed 53 // and destructed with the same functions as non-qualified objects. 54 // unfortunately, lvalue is considered a qualifier. For AddressExpr to resolve, its argument 55 // must have an lvalue qualified type, so remove all qualifiers except lvalue. If we ever 56 // remove lvalue as a qualifier, this can change to 57 // type->get_qualifiers() = Type::Qualifiers(); 58 assert( type ); 59 Type * castType = type->clone(); 60 // castType->get_qualifiers() -= Type::Qualifiers(true, true, true, false, true, false); 61 castType->get_qualifiers() -= Type::Qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic ); 62 castType->set_lvalue( true ); // xxx - might not need this 63 dstParam = new CastExpr( dstParam, new PointerType( Type::Qualifiers(), castType ) ); 63 64 } 64 65 fExpr->get_args().push_back( dstParam ); … … 74 75 75 76 return listInit; 77 } 78 79 /// Store in out a loop which calls fname on each element of the array with srcParam and dstParam as arguments. 80 /// If forward is true, loop goes from 0 to N-1, else N-1 to 0 81 template< typename OutputIterator > 82 void genArrayCall( InitTweak::InitExpander & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, bool addCast = false, bool forward = true ) { 83 static UniqueName indexName( "_index" ); 84 85 // for a flexible array member nothing is done -- user must define own assignment 86 if ( ! array->get_dimension() ) return ; 87 88 Expression * begin, * end, * update, * cmp; 89 if ( forward ) { 90 // generate: for ( int i = 0; i < N; ++i ) 91 begin = new ConstantExpr( Constant::from_int( 0 ) ); 92 end = array->get_dimension()->clone(); 93 cmp = new NameExpr( "?<?" ); 94 update = new NameExpr( "++?" ); 95 } else { 96 // generate: for ( int i = N-1; i >= 0; --i ) 97 begin = new UntypedExpr( new NameExpr( "?-?" ) ); 98 ((UntypedExpr*)begin)->get_args().push_back( array->get_dimension()->clone() ); 99 ((UntypedExpr*)begin)->get_args().push_back( new ConstantExpr( Constant::from_int( 1 ) ) ); 100 end = new ConstantExpr( Constant::from_int( 0 ) ); 101 cmp = new NameExpr( "?>=?" ); 102 update = new NameExpr( "--?" ); 76 103 } 77 104 78 /// Store in out a loop which calls fname on each element of the array with srcParam and dstParam as arguments. 79 /// If forward is true, loop goes from 0 to N-1, else N-1 to 0 80 template< typename OutputIterator > 81 void genArrayCall( InitTweak::InitExpander & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, bool addCast = false, bool forward = true ) { 82 static UniqueName indexName( "_index" ); 105 ObjectDecl *index = new ObjectDecl( indexName.newName(), Type::StorageClasses(), LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), new SingleInit( begin, std::list<Expression*>() ) ); 83 106 84 // for a flexible array member nothing is done -- user must define own assignment 85 if ( ! array->get_dimension() ) return ; 107 UntypedExpr *cond = new UntypedExpr( cmp ); 108 cond->get_args().push_back( new VariableExpr( index ) ); 109 cond->get_args().push_back( end ); 86 110 87 Expression * begin, * end, * update, * cmp; 88 if ( forward ) { 89 // generate: for ( int i = 0; i < N; ++i ) 90 begin = new ConstantExpr( Constant::from_int( 0 ) ); 91 end = array->get_dimension()->clone(); 92 cmp = new NameExpr( "?<?" ); 93 update = new NameExpr( "++?" ); 94 } else { 95 // generate: for ( int i = N-1; i >= 0; --i ) 96 begin = new UntypedExpr( new NameExpr( "?-?" ) ); 97 ((UntypedExpr*)begin)->get_args().push_back( array->get_dimension()->clone() ); 98 ((UntypedExpr*)begin)->get_args().push_back( new ConstantExpr( Constant::from_int( 1 ) ) ); 99 end = new ConstantExpr( Constant::from_int( 0 ) ); 100 cmp = new NameExpr( "?>=?" ); 101 update = new NameExpr( "--?" ); 102 } 111 UntypedExpr *inc = new UntypedExpr( update ); 112 inc->get_args().push_back( new AddressExpr( new VariableExpr( index ) ) ); 103 113 104 ObjectDecl *index = new ObjectDecl( indexName.newName(), Type::StorageClasses(), LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), new SingleInit( begin ) ); 114 UntypedExpr *dstIndex = new UntypedExpr( new NameExpr( "?[?]" ) ); 115 dstIndex->get_args().push_back( dstParam ); 116 dstIndex->get_args().push_back( new VariableExpr( index ) ); 117 dstParam = dstIndex; 105 118 106 UntypedExpr *cond = new UntypedExpr( cmp );107 cond->get_args().push_back( new VariableExpr( index ) );108 cond->get_args().push_back( end);119 // srcParam must keep track of the array indices to build the 120 // source parameter and/or array list initializer 121 srcParam.addArrayIndex( new VariableExpr( index ), array->get_dimension()->clone() ); 109 122 110 UntypedExpr *inc = new UntypedExpr( update ); 111 inc->get_args().push_back( new AddressExpr( new VariableExpr( index ) ) ); 123 // for stmt's body, eventually containing call 124 CompoundStmt * body = new CompoundStmt( noLabels ); 125 Statement * listInit = genCall( srcParam, dstParam, fname, back_inserter( body->get_kids() ), array->get_base(), addCast, forward ); 112 126 113 UntypedExpr *dstIndex = new UntypedExpr( new NameExpr( "?[?]" ) ); 114 dstIndex->get_args().push_back( dstParam ); 115 dstIndex->get_args().push_back( new VariableExpr( index ) ); 116 dstParam = dstIndex; 127 // block containing for stmt and index variable 128 std::list<Statement *> initList; 129 CompoundStmt * block = new CompoundStmt( noLabels ); 130 block->get_kids().push_back( new DeclStmt( noLabels, index ) ); 131 if ( listInit ) block->get_kids().push_back( listInit ); 132 block->get_kids().push_back( new ForStmt( noLabels, initList, cond, inc, body ) ); 117 133 118 // srcParam must keep track of the array indices to build the 119 // source parameter and/or array list initializer 120 srcParam.addArrayIndex( new VariableExpr( index ), array->get_dimension()->clone() ); 134 *out++ = block; 135 } 121 136 122 // for stmt's body, eventually containing call 123 CompoundStmt * body = new CompoundStmt( noLabels ); 124 Statement * listInit = genCall( srcParam, dstParam, fname, back_inserter( body->get_kids() ), array->get_base(), addCast, forward ); 137 template< typename OutputIterator > 138 Statement * genCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, bool addCast, bool forward ) { 139 if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) { 140 genArrayCall( srcParam, dstParam, fname, out, at, addCast, forward ); 141 return 0; 142 } else { 143 return genScalarCall( srcParam, dstParam, fname, out, type, addCast ); 144 } 145 } 125 146 126 // block containing for stmt and index variable 127 std::list<Statement *> initList; 128 CompoundStmt * block = new CompoundStmt( noLabels ); 129 block->get_kids().push_back( new DeclStmt( noLabels, index ) ); 130 if ( listInit ) block->get_kids().push_back( listInit ); 131 block->get_kids().push_back( new ForStmt( noLabels, initList, cond, inc, body ) ); 147 /// inserts into out a generated call expression to function fname with arguments dstParam 148 /// and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls. decl is the 149 /// object being constructed. The function wraps constructor and destructor calls in an 150 /// ImplicitCtorDtorStmt node. 151 template< typename OutputIterator > 152 void genImplicitCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, DeclarationWithType * decl, bool forward = true ) { 153 ObjectDecl *obj = dynamic_cast<ObjectDecl *>( decl ); 154 assert( obj ); 155 // unnamed bit fields are not copied as they cannot be accessed 156 if ( isUnnamedBitfield( obj ) ) return; 132 157 133 *out++ = block; 158 bool addCast = (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && obj->get_bitfieldWidth() == NULL ) ); 159 std::list< Statement * > stmts; 160 genCall( srcParam, dstParam, fname, back_inserter( stmts ), obj->get_type(), addCast, forward ); 161 162 // currently genCall should produce at most one element, but if that changes then the next line needs to be updated to grab the statement which contains the call 163 assert( stmts.size() <= 1 ); 164 if ( stmts.size() == 1 ) { 165 Statement * callStmt = stmts.front(); 166 if ( addCast ) { 167 // implicitly generated ctor/dtor calls should be wrapped 168 // so that later passes are aware they were generated. 169 // xxx - don't mark as an implicit ctor/dtor if obj is a bitfield, 170 // because this causes the address to be taken at codegen, which is illegal in C. 171 callStmt = new ImplicitCtorDtorStmt( callStmt ); 172 } 173 *out++ = callStmt; 134 174 } 135 136 template< typename OutputIterator > 137 Statement * genCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, bool addCast, bool forward ) { 138 if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) { 139 genArrayCall( srcParam, dstParam, fname, out, at, addCast, forward ); 140 return 0; 141 } else { 142 return genScalarCall( srcParam, dstParam, fname, out, type, addCast ); 143 } 144 } 145 146 /// inserts into out a generated call expression to function fname with arguments dstParam 147 /// and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls. decl is the 148 /// object being constructed. The function wraps constructor and destructor calls in an 149 /// ImplicitCtorDtorStmt node. 150 template< typename OutputIterator > 151 void genImplicitCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, DeclarationWithType * decl, bool forward = true ) { 152 ObjectDecl *obj = dynamic_cast<ObjectDecl *>( decl ); 153 assert( obj ); 154 // unnamed bit fields are not copied as they cannot be accessed 155 if ( isUnnamedBitfield( obj ) ) return; 156 157 bool addCast = (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && obj->get_bitfieldWidth() == NULL ) ); 158 std::list< Statement * > stmts; 159 genCall( srcParam, dstParam, fname, back_inserter( stmts ), obj->get_type(), addCast, forward ); 160 161 // currently genCall should produce at most one element, but if that changes then the next line needs to be updated to grab the statement which contains the call 162 assert( stmts.size() <= 1 ); 163 if ( stmts.size() == 1 ) { 164 Statement * callStmt = stmts.front(); 165 if ( addCast ) { 166 // implicitly generated ctor/dtor calls should be wrapped 167 // so that later passes are aware they were generated. 168 // xxx - don't mark as an implicit ctor/dtor if obj is a bitfield, 169 // because this causes the address to be taken at codegen, which is illegal in C. 170 callStmt = new ImplicitCtorDtorStmt( callStmt ); 171 } 172 *out++ = callStmt; 173 } 174 } 175 } 175 176 } // namespace SymTab 176 177 #endif // AUTOGEN_H -
src/SymTab/ImplementationType.cc
r67fa9f9 r11dbfe1 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // ImplementationType.cc -- 7 // ImplementationType.cc -- 8 8 // 9 9 // Author : Richard C. Bilson … … 92 92 93 93 void ImplementationType::visit(TupleType *tupleType) { 94 std::list< Type * > types;94 TupleType *newType = new TupleType( Type::Qualifiers() ); 95 95 for ( std::list< Type* >::iterator i = tupleType->get_types().begin(); i != tupleType->get_types().end(); ++i ) { 96 96 Type *implType = implementationType( *i, indexer ); 97 97 implType->get_qualifiers() |= tupleType->get_qualifiers(); 98 types.push_back( implType );98 newType->get_types().push_back( implType ); 99 99 } // for 100 result = new TupleType( Type::Qualifiers(), types );100 result = newType; 101 101 } 102 102 -
src/SymTab/Indexer.cc
r67fa9f9 r11dbfe1 652 652 for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) { 653 653 // check for C decls with the same name, skipping those with a compatible type (by mangleName) 654 if ( ! LinkageSpec::isMangled( decl->second->get_linkage() )&& decl->first != mangleName ) return true;654 if ( decl->second->get_linkage() == LinkageSpec::C && decl->first != mangleName ) return true; 655 655 } 656 656 } … … 669 669 // check for C decls with the same name, skipping 670 670 // those with an incompatible type (by mangleName) 671 if ( ! LinkageSpec::isMangled( decl->second->get_linkage() )&& decl->first == mangleName ) return true;671 if ( decl->second->get_linkage() == LinkageSpec::C && decl->first == mangleName ) return true; 672 672 } 673 673 } … … 724 724 // new definition shadows the autogenerated one, even at the same scope 725 725 return false; 726 } else if ( LinkageSpec::isMangled( added->get_linkage() )|| ResolvExpr::typesCompatible( added->get_type(), existing->get_type(), Indexer() ) ) {726 } else if ( added->get_linkage() != LinkageSpec::C || ResolvExpr::typesCompatible( added->get_type(), existing->get_type(), Indexer() ) ) { 727 727 // typesCompatible doesn't really do the right thing here. When checking compatibility of function types, 728 728 // we should ignore outermost pointer qualifiers, except _Atomic? … … 765 765 766 766 // this ensures that no two declarations with the same unmangled name at the same scope both have C linkage 767 if ( ! LinkageSpec::isMangled( decl->get_linkage() )) {767 if ( decl->get_linkage() == LinkageSpec::C ) { 768 768 // NOTE this is broken in Richard's original code in such a way that it never triggers (it 769 769 // doesn't check decls that have the same manglename, and all C-linkage decls are defined to -
src/SymTab/Validate.cc
r67fa9f9 r11dbfe1 106 106 107 107 /// Fix return types so that every function returns exactly one value 108 struct ReturnTypeFixer { 108 class ReturnTypeFixer { 109 public: 109 110 static void fix( std::list< Declaration * > &translationUnit ); 110 111 … … 114 115 115 116 /// Replaces enum types by int, and function or array types in function parameter and return lists by appropriate pointers. 116 struct EnumAndPointerDecay { 117 class EnumAndPointerDecay { 118 public: 117 119 void previsit( EnumDecl *aggregateDecl ); 118 120 void previsit( FunctionType *func ); … … 157 159 }; 158 160 159 struct ReturnChecker : public WithGuards { 161 class ReturnChecker : public WithScopes { 162 public: 160 163 /// Checks that return statements return nothing if their return type is void 161 164 /// and return something if the return type is non-void. 162 165 static void checkFunctionReturns( std::list< Declaration * > & translationUnit ); 163 166 private: 164 167 void previsit( FunctionDecl * functionDecl ); 165 168 void previsit( ReturnStmt * returnStmt ); … … 202 205 }; 203 206 204 struct VerifyCtorDtorAssign { 207 class VerifyCtorDtorAssign { 208 public: 205 209 /// ensure that constructors, destructors, and assignment have at least one 206 210 /// parameter, the first of which must be a pointer, and that ctor/dtors have no … … 212 216 213 217 /// ensure that generic types have the correct number of type arguments 214 struct ValidateGenericParameters { 218 class ValidateGenericParameters { 219 public: 215 220 void previsit( StructInstType * inst ); 216 221 void previsit( UnionInstType * inst ); 217 222 }; 218 223 219 struct ArrayLength { 224 class ArrayLength { 225 public: 220 226 /// for array types without an explicit length, compute the length and store it so that it 221 227 /// is known to the rest of the phases. For example, … … 230 236 }; 231 237 232 struct CompoundLiteral final : public WithDeclsToAdd, public WithVisitorRef<CompoundLiteral>{238 class CompoundLiteral final : public GenPoly::DeclMutator { 233 239 Type::StorageClasses storageClasses; 234 240 235 void premutate( ObjectDecl *objectDecl ); 236 Expression * postmutate( CompoundLiteralExpr *compLitExpr ); 241 using GenPoly::DeclMutator::mutate; 242 DeclarationWithType * mutate( ObjectDecl *objectDecl ) final; 243 Expression *mutate( CompoundLiteralExpr *compLitExpr ) final; 237 244 }; 238 245 … … 241 248 LinkReferenceToTypes lrt( doDebug, 0 ); 242 249 ForallPointerDecay fpd( 0 ); 243 PassVisitor<CompoundLiteral>compoundliteral;250 CompoundLiteral compoundliteral; 244 251 PassVisitor<ValidateGenericParameters> genericParams; 245 252 … … 256 263 Concurrency::implementThreadStarter( translationUnit ); 257 264 ReturnChecker::checkFunctionReturns( translationUnit ); 258 mutateAll( translationUnit, compoundliteral);265 compoundliteral.mutateDeclarationList( translationUnit ); 259 266 acceptAll( translationUnit, fpd ); 260 267 ArrayLength::computeLength( translationUnit ); … … 876 883 } 877 884 878 void CompoundLiteral::premutate( ObjectDecl *objectDecl ) {885 DeclarationWithType * CompoundLiteral::mutate( ObjectDecl *objectDecl ) { 879 886 storageClasses = objectDecl->get_storageClasses(); 880 } 881 882 Expression *CompoundLiteral::postmutate( CompoundLiteralExpr *compLitExpr ) { 887 DeclarationWithType * temp = Mutator::mutate( objectDecl ); 888 return temp; 889 } 890 891 Expression *CompoundLiteral::mutate( CompoundLiteralExpr *compLitExpr ) { 883 892 // transform [storage_class] ... (struct S){ 3, ... }; 884 893 // into [storage_class] struct S temp = { 3, ... }; 885 894 static UniqueName indexName( "_compLit" ); 886 895 887 ObjectDecl *tempvar = new ObjectDecl( indexName.newName(), storageClasses, LinkageSpec::C, nullptr, compLitExpr->get_result(), compLitExpr->get_initializer() );888 compLitExpr->set_result( nullptr);889 compLitExpr->set_initializer( nullptr);896 ObjectDecl *tempvar = new ObjectDecl( indexName.newName(), storageClasses, LinkageSpec::C, 0, compLitExpr->get_result(), compLitExpr->get_initializer() ); 897 compLitExpr->set_result( 0 ); 898 compLitExpr->set_initializer( 0 ); 890 899 delete compLitExpr; 891 declsToAddBefore.push_back( tempvar ); // add modified temporary to current block 892 return new VariableExpr( tempvar ); 900 DeclarationWithType * newtempvar = mutate( tempvar ); 901 addDeclaration( newtempvar ); // add modified temporary to current block 902 return new VariableExpr( newtempvar ); 893 903 } 894 904 -
src/SynTree/Constant.cc
r67fa9f9 r11dbfe1 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // Constant.cc -- 7 // Constant.cc -- 8 8 // 9 9 // Author : Richard C. Bilson … … 46 46 } 47 47 48 unsigned long long Constant::get_ival() const {49 assertf( safe_dynamic_cast<BasicType*>(type)->isInteger(), "Attempt to retrieve ival from non-integer constant." );50 return val.ival;51 }52 53 double Constant::get_dval() const {54 assertf( ! safe_dynamic_cast<BasicType*>(type)->isInteger(), "Attempt to retrieve dval from integer constant." );55 return val.dval;56 }57 58 48 void Constant::print( std::ostream &os ) const { 59 49 os << "(" << rep << " " << val.ival; -
src/SynTree/Constant.h
r67fa9f9 r11dbfe1 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // Constant.h -- 7 // Constant.h -- 8 8 // 9 9 // Author : Richard C. Bilson … … 32 32 std::string & get_value() { return rep; } 33 33 void set_value( std::string newValue ) { rep = newValue; } 34 unsigned long long get_ival() const;35 double get_dval() const;36 34 37 35 /// generates a boolean constant of the given bool -
src/SynTree/Expression.cc
r67fa9f9 r11dbfe1 21 21 #include <iterator> 22 22 23 #include "Type.h" 24 #include "Initializer.h" 25 #include "Expression.h" 23 26 #include "Declaration.h" 24 #include "Expression.h"25 #include "Initializer.h"26 27 #include "Statement.h" 27 #include "Type.h"28 28 #include "TypeSubstitution.h" 29 #include "VarExprReplacer.h"30 31 29 #include "Common/utility.h" 32 #include "Common/PassVisitor.h"33 34 30 #include "InitTweak/InitTweak.h" 35 31 … … 96 92 97 93 Declaration *decl = get_var(); 94 // if ( decl != 0) decl->print(os, indent + 2); 98 95 if ( decl != 0) decl->printShort(os, indent + 2); 99 96 os << std::endl; … … 660 657 } 661 658 662 InitAlternative::InitAlternative( Type * type, Designation * designation ) : type( type ), designation( designation ) {}663 InitAlternative::InitAlternative( const InitAlternative & other ) : type( maybeClone( other.type ) ), designation( maybeClone( other.designation ) ) {}664 InitAlternative::~InitAlternative() {665 delete type;666 delete designation;667 }668 669 UntypedInitExpr::UntypedInitExpr( Expression * expr, const std::list<InitAlternative> & initAlts ) : expr( expr ), initAlts( initAlts ) {}670 UntypedInitExpr::UntypedInitExpr( const UntypedInitExpr & other ) : Expression( other ), expr( maybeClone( other.expr ) ), initAlts( other.initAlts ) {}671 UntypedInitExpr::~UntypedInitExpr() {672 delete expr;673 }674 675 void UntypedInitExpr::print( std::ostream & os, int indent ) const {676 os << "Untyped Init Expression" << std::endl << std::string( indent+2, ' ' );677 expr->print( os, indent+2 );678 if ( ! initAlts.empty() ) {679 for ( const InitAlternative & alt : initAlts ) {680 os << std::string( indent+2, ' ' ) << "InitAlternative: ";681 alt.type->print( os, indent+2 );682 alt.designation->print( os, indent+2 );683 }684 }685 }686 687 InitExpr::InitExpr( Expression * expr, Designation * designation ) : expr( expr ), designation( designation ) {688 set_result( expr->get_result()->clone() );689 }690 InitExpr::InitExpr( const InitExpr & other ) : Expression( other ), expr( maybeClone( other.expr ) ), designation( maybeClone( other.designation) ) {}691 InitExpr::~InitExpr() {692 delete expr;693 delete designation;694 }695 696 void InitExpr::print( std::ostream & os, int indent ) const {697 os << "Init Expression" << std::endl << std::string( indent+2, ' ' );698 expr->print( os, indent+2 );699 os << std::string( indent+2, ' ' ) << "with designation: ";700 designation->print( os, indent+2 );701 }702 703 704 659 std::ostream & operator<<( std::ostream & out, const Expression * expr ) { 705 660 if ( expr ) { -
src/SynTree/Expression.h
r67fa9f9 r11dbfe1 744 744 }; 745 745 746 struct InitAlternative {747 public:748 Type * type = nullptr;749 Designation * designation = nullptr;750 InitAlternative( Type * type, Designation * designation );751 InitAlternative( const InitAlternative & other );752 InitAlternative & operator=( const Initializer & other ) = delete; // at the moment this isn't used, and I don't want to implement it753 ~InitAlternative();754 };755 756 class UntypedInitExpr : public Expression {757 public:758 UntypedInitExpr( Expression * expr, const std::list<InitAlternative> & initAlts );759 UntypedInitExpr( const UntypedInitExpr & other );760 ~UntypedInitExpr();761 762 Expression * get_expr() const { return expr; }763 UntypedInitExpr * set_expr( Expression * newValue ) { expr = newValue; return this; }764 765 std::list<InitAlternative> & get_initAlts() { return initAlts; }766 767 virtual UntypedInitExpr * clone() const { return new UntypedInitExpr( * this ); }768 virtual void accept( Visitor & v ) { v.visit( this ); }769 virtual Expression * acceptMutator( Mutator & m ) { return m.mutate( this ); }770 virtual void print( std::ostream & os, int indent = 0 ) const;771 private:772 Expression * expr;773 std::list<InitAlternative> initAlts;774 };775 776 class InitExpr : public Expression {777 public:778 InitExpr( Expression * expr, Designation * designation );779 InitExpr( const InitExpr & other );780 ~InitExpr();781 782 Expression * get_expr() const { return expr; }783 InitExpr * set_expr( Expression * newValue ) { expr = newValue; return this; }784 785 Designation * get_designation() const { return designation; }786 InitExpr * set_designation( Designation * newValue ) { designation = newValue; return this; }787 788 virtual InitExpr * clone() const { return new InitExpr( * this ); }789 virtual void accept( Visitor & v ) { v.visit( this ); }790 virtual Expression * acceptMutator( Mutator & m ) { return m.mutate( this ); }791 virtual void print( std::ostream & os, int indent = 0 ) const;792 private:793 Expression * expr;794 Designation * designation;795 };796 797 798 746 std::ostream & operator<<( std::ostream & out, const Expression * expr ); 799 747 -
src/SynTree/Initializer.cc
r67fa9f9 r11dbfe1 19 19 #include "Common/utility.h" 20 20 21 Designation::Designation( const std::list< Expression * > & designators ) : designators( designators ) {}22 Designation::Designation( const Designation & other ) : BaseSyntaxNode( other ) {23 // std::cerr << "cloning designation" << std::endl;24 cloneAll( other.designators, designators );25 // std::cerr << "finished cloning designation" << std::endl;26 }27 28 Designation::~Designation() {29 // std::cerr << "destroying designation" << std::endl;30 deleteAll( designators );31 // std::cerr << "finished destroying designation" << std::endl;32 }33 34 void Designation::print( std::ostream &os, int indent ) const {35 if ( ! designators.empty() ) {36 os << std::string(indent + 2, ' ' ) << "designated by: " << std::endl;37 for ( std::list < Expression * >::const_iterator i = designators.begin(); i != designators.end(); i++ ) {38 os << std::string(indent + 4, ' ' );39 ( *i )->print(os, indent + 4 );40 }41 os << std::endl;42 } // if43 }44 45 21 Initializer::Initializer( bool maybeConstructed ) : maybeConstructed( maybeConstructed ) {} 46 22 Initializer::Initializer( const Initializer & other ) : BaseSyntaxNode( other ), maybeConstructed( other.maybeConstructed ) { 47 23 } 24 25 48 26 Initializer::~Initializer() {} 49 27 50 SingleInit::SingleInit( Expression *v, bool maybeConstructed ) : Initializer( maybeConstructed ), value ( v ) { 28 std::string Initializer::designator_name( Expression *des ) { 29 if ( NameExpr *n = dynamic_cast<NameExpr *>(des) ) 30 return n->get_name(); 31 else 32 throw 0; 33 } 34 35 // void Initializer::print( __attribute__((unused)) std::ostream &os, __attribute__((unused)) int indent ) {} 36 37 SingleInit::SingleInit( Expression *v, const std::list< Expression *> &_designators, bool maybeConstructed ) : Initializer( maybeConstructed ), value ( v ), designators( _designators ) { 51 38 } 52 39 53 40 SingleInit::SingleInit( const SingleInit &other ) : Initializer(other), value ( maybeClone( other.value ) ) { 41 cloneAll(other.designators, designators ); 54 42 } 55 43 56 44 SingleInit::~SingleInit() { 57 45 delete value; 46 deleteAll(designators); 58 47 } 59 48 60 void SingleInit::print( std::ostream &os, int indent ) const{61 os << std:: string(indent, ' ' ) << "Simple Initializer: " << std::endl;49 void SingleInit::print( std::ostream &os, int indent ) { 50 os << std::endl << std::string(indent, ' ' ) << "Simple Initializer: " << std::endl; 62 51 os << std::string(indent+4, ' ' ); 63 52 value->print( os, indent+4 ); 53 54 if ( ! designators.empty() ) { 55 os << std::endl << std::string(indent + 2, ' ' ) << "designated by: " << std::endl; 56 for ( std::list < Expression * >::iterator i = designators.begin(); i != designators.end(); i++ ) { 57 os << std::string(indent + 4, ' ' ); 58 ( *i )->print(os, indent + 4 ); 59 } 60 } // if 64 61 } 65 62 66 67 ListInit::ListInit( const std::list<Initializer*> &inits, const std::list<Designation *> &des, bool maybeConstructed ) 68 : Initializer( maybeConstructed ), initializers( inits ), designations( des ) { 69 // handle the common case where a ListInit is created without designations by making a list of empty designations with the same length as the initializer 70 if ( designations.empty() ) { 71 for ( auto & i : initializers ) { 72 (void)i; 73 designations.push_back( new Designation( {} ) ); 74 } 75 } 76 assertf( initializers.size() == designations.size(), "Created ListInit with mismatching initializers (%d) and designations (%d)", initializers.size(), designations.size() ); 63 ListInit::ListInit( const std::list<Initializer*> &_initializers, const std::list<Expression *> &_designators, bool maybeConstructed ) 64 : Initializer( maybeConstructed ), initializers( _initializers ), designators( _designators ) { 77 65 } 78 66 79 67 ListInit::ListInit( const ListInit & other ) : Initializer( other ) { 80 68 cloneAll( other.initializers, initializers ); 81 cloneAll( other.designat ions, designations );69 cloneAll( other.designators, designators ); 82 70 } 71 83 72 84 73 ListInit::~ListInit() { 85 74 deleteAll( initializers ); 86 deleteAll( designat ions );75 deleteAll( designators ); 87 76 } 88 77 89 void ListInit::print( std::ostream &os, int indent ) const { 90 os << std::string(indent, ' ') << "Compound initializer: " << std::endl; 91 for ( Designation * d : designations ) { 92 d->print( os, indent + 2 ); 93 } 78 void ListInit::print( std::ostream &os, int indent ) { 79 os << std::endl << std::string(indent, ' ') << "Compound initializer: "; 80 if ( ! designators.empty() ) { 81 os << std::string(indent + 2, ' ' ) << "designated by: ["; 82 for ( std::list < Expression * >::iterator i = designators.begin(); 83 i != designators.end(); i++ ) { 84 ( *i )->print(os, indent + 4 ); 85 } // for 94 86 95 for ( const Initializer * init : initializers ) { 96 init->print( os, indent + 2 ); 97 os << std::endl; 98 } 87 os << std::string(indent + 2, ' ' ) << "]"; 88 } // if 89 90 for ( std::list<Initializer *>::iterator i = initializers.begin(); i != initializers.end(); i++ ) 91 (*i)->print( os, indent + 2 ); 99 92 } 100 93 … … 110 103 } 111 104 112 void ConstructorInit::print( std::ostream &os, int indent ) const{105 void ConstructorInit::print( std::ostream &os, int indent ) { 113 106 os << std::endl << std::string(indent, ' ') << "Constructor initializer: " << std::endl; 114 107 if ( ctor ) { … … 131 124 } 132 125 133 std::ostream & operator<<( std::ostream & out, const Initializer * init ) { 134 if ( init ) { 135 init->print( out ); 136 } else { 137 out << "nullptr"; 138 } 139 return out; 140 } 141 142 std::ostream & operator<<( std::ostream & out, const Designation * des ) { 143 if ( des ) { 144 des->print( out ); 145 } else { 146 out << "nullptr"; 147 } 126 std::ostream & operator<<( std::ostream & out, Initializer * init ) { 127 init->print( out ); 148 128 return out; 149 129 } -
src/SynTree/Initializer.h
r67fa9f9 r11dbfe1 25 25 #include "Visitor.h" 26 26 27 // Designation: list of designator (NameExpr, VariableExpr, and ConstantExpr) expressions that specify an object being initialized. 28 class Designation : public BaseSyntaxNode { 29 public: 30 Designation( const std::list< Expression * > & designators ); 31 Designation( const Designation & other ); 32 virtual ~Designation(); 33 34 std::list< Expression * > & get_designators() { return designators; } 35 36 virtual Designation * clone() const { return new Designation( *this ); }; 37 virtual void accept( Visitor &v ) { v.visit( this ); } 38 virtual Designation * acceptMutator( Mutator &m ) { return m.mutate( this ); } 39 virtual void print( std::ostream &os, int indent = 0 ) const; 40 private: 41 std::list< Expression * > designators; 42 }; 43 44 const std::list<Designation *> noDesignators; 27 const std::list<Expression*> noDesignators; 45 28 46 29 // Initializer: base class for object initializers (provide default values) 47 30 class Initializer : public BaseSyntaxNode { 48 31 public: 32 // Initializer( std::string _name = std::string(""), int _pos = 0 ); 49 33 Initializer( bool maybeConstructed ); 50 34 Initializer( const Initializer & other ); 51 35 virtual ~Initializer(); 36 37 static std::string designator_name( Expression *designator ); 38 39 // void set_name( std::string newValue ) { name = newValue; } 40 // std::string get_name() const { return name; } 41 42 // void set_pos( int newValue ) { pos = newValue; } 43 // int get_pos() const { return pos; } 44 virtual void set_designators( std::list<Expression *> & ) { assert(false); } 45 virtual std::list<Expression *> &get_designators() { 46 assert(false); 47 std::list<Expression *> *ret = 0; return *ret; // never reached 48 } 52 49 53 50 bool get_maybeConstructed() { return maybeConstructed; } … … 56 53 virtual void accept( Visitor &v ) = 0; 57 54 virtual Initializer *acceptMutator( Mutator &m ) = 0; 58 virtual void print( std::ostream &os, int indent = 0 ) const= 0;55 virtual void print( std::ostream &os, int indent = 0 ) = 0; 59 56 private: 57 // std::string name; 58 // int pos; 60 59 bool maybeConstructed; 61 60 }; … … 64 63 class SingleInit : public Initializer { 65 64 public: 66 SingleInit( Expression *value, bool maybeConstructed = false );65 SingleInit( Expression *value, const std::list< Expression *> &designators = std::list< Expression * >(), bool maybeConstructed = false ); 67 66 SingleInit( const SingleInit &other ); 68 67 virtual ~SingleInit(); … … 71 70 void set_value( Expression *newValue ) { value = newValue; } 72 71 72 std::list<Expression *> &get_designators() { return designators; } 73 void set_designators( std::list<Expression *> &newValue ) { designators = newValue; } 74 73 75 virtual SingleInit *clone() const { return new SingleInit( *this); } 74 76 virtual void accept( Visitor &v ) { v.visit( this ); } 75 77 virtual Initializer *acceptMutator( Mutator &m ) { return m.mutate( this ); } 76 virtual void print( std::ostream &os, int indent = 0 ) const;78 virtual void print( std::ostream &os, int indent = 0 ); 77 79 private: 78 80 //Constant *value; 79 81 Expression *value; // has to be a compile-time constant 82 std::list< Expression * > designators; 80 83 }; 81 84 … … 85 88 public: 86 89 ListInit( const std::list<Initializer*> &initializers, 87 const std::list< Designation *> &designators = {}, bool maybeConstructed = false );90 const std::list<Expression *> &designators = std::list< Expression * >(), bool maybeConstructed = false ); 88 91 ListInit( const ListInit & other ); 89 92 virtual ~ListInit(); 90 93 91 std::list<Designation *> & get_designations() { return designations; } 92 std::list<Initializer *> & get_initializers() { return initializers; } 94 void set_designators( std::list<Expression *> &newValue ) { designators = newValue; } 95 std::list<Expression *> &get_designators() { return designators; } 96 void set_initializers( std::list<Initializer*> &newValue ) { initializers = newValue; } 97 std::list<Initializer*> &get_initializers() { return initializers; } 93 98 94 99 typedef std::list<Initializer*>::iterator iterator; 95 typedef std::list<Initializer*>::const_iterator const_iterator;96 100 iterator begin() { return initializers.begin(); } 97 101 iterator end() { return initializers.end(); } 98 const_iterator begin() const { return initializers.begin(); }99 const_iterator end() const { return initializers.end(); }100 102 101 103 virtual ListInit *clone() const { return new ListInit( *this ); } 102 104 virtual void accept( Visitor &v ) { v.visit( this ); } 103 105 virtual Initializer *acceptMutator( Mutator &m ) { return m.mutate( this ); } 104 virtual void print( std::ostream &os, int indent = 0 ) const;106 virtual void print( std::ostream &os, int indent = 0 ); 105 107 private: 106 std::list<Initializer *> initializers; // order *is* important107 std::list< Designation *> designations; // order/length is consistent with initializers108 std::list<Initializer*> initializers; // order *is* important 109 std::list<Expression *> designators; 108 110 }; 109 111 … … 128 130 virtual void accept( Visitor &v ) { v.visit( this ); } 129 131 virtual Initializer *acceptMutator( Mutator &m ) { return m.mutate( this ); } 130 virtual void print( std::ostream &os, int indent = 0 ) const;132 virtual void print( std::ostream &os, int indent = 0 ); 131 133 132 134 private: … … 138 140 }; 139 141 140 std::ostream & operator<<( std::ostream & out, const Initializer * init ); 141 std::ostream & operator<<( std::ostream & out, const Designation * des ); 142 std::ostream & operator<<( std::ostream & out, Initializer * init ); 142 143 143 144 #endif // INITIALIZER_H -
src/SynTree/Mutator.cc
r67fa9f9 r11dbfe1 433 433 } 434 434 435 Expression *Mutator::mutate( UntypedInitExpr * initExpr ) {436 initExpr->set_env( maybeMutate( initExpr->get_env(), *this ) );437 initExpr->set_result( maybeMutate( initExpr->get_result(), *this ) );438 initExpr->set_expr( maybeMutate( initExpr->get_expr(), *this ) );439 // not currently mutating initAlts, but this doesn't matter since this node is only used in the resolver.440 return initExpr;441 }442 443 Expression *Mutator::mutate( InitExpr * initExpr ) {444 initExpr->set_env( maybeMutate( initExpr->get_env(), *this ) );445 initExpr->set_result( maybeMutate( initExpr->get_result(), *this ) );446 initExpr->set_expr( maybeMutate( initExpr->get_expr(), *this ) );447 initExpr->set_designation( maybeMutate( initExpr->get_designation(), *this ) );448 return initExpr;449 }450 451 435 452 436 Type *Mutator::mutate( VoidType *voidType ) { … … 515 499 mutateAll( tupleType->get_forall(), *this ); 516 500 mutateAll( tupleType->get_types(), *this ); 517 mutateAll( tupleType->get_members(), *this );518 501 return tupleType; 519 502 } … … 552 535 553 536 554 Designation *Mutator::mutate( Designation * designation ) {555 mutateAll( designation->get_designators(), *this );556 return designation;557 }558 559 537 Initializer *Mutator::mutate( SingleInit *singleInit ) { 560 538 singleInit->set_value( singleInit->get_value()->acceptMutator( *this ) ); … … 563 541 564 542 Initializer *Mutator::mutate( ListInit *listInit ) { 565 mutateAll( listInit->get_designat ions(), *this );543 mutateAll( listInit->get_designators(), *this ); 566 544 mutateAll( listInit->get_initializers(), *this ); 567 545 return listInit; -
src/SynTree/Mutator.h
r67fa9f9 r11dbfe1 85 85 virtual Expression* mutate( StmtExpr * stmtExpr ); 86 86 virtual Expression* mutate( UniqueExpr * uniqueExpr ); 87 virtual Expression* mutate( UntypedInitExpr * initExpr );88 virtual Expression* mutate( InitExpr * initExpr );89 87 90 88 virtual Type* mutate( VoidType *basicType ); … … 105 103 virtual Type* mutate( OneType *oneType ); 106 104 107 virtual Designation* mutate( Designation *designation );108 105 virtual Initializer* mutate( SingleInit *singleInit ); 109 106 virtual Initializer* mutate( ListInit *listInit ); -
src/SynTree/SynTree.h
r67fa9f9 r11dbfe1 93 93 class StmtExpr; 94 94 class UniqueExpr; 95 class UntypedInitExpr;96 class InitExpr;97 95 98 96 class Type; … … 115 113 class OneType; 116 114 117 class Designation;118 115 class Initializer; 119 116 class SingleInit; -
src/SynTree/TupleType.cc
r67fa9f9 r11dbfe1 14 14 // 15 15 16 #include "Declaration.h"17 #include "Initializer.h"18 16 #include "Type.h" 19 17 #include "Common/utility.h" 20 #include "Parser/LinkageSpec.h"21 18 22 19 TupleType::TupleType( const Type::Qualifiers &tq, const std::list< Type * > & types, const std::list< Attribute * > & attributes ) : Type( tq, attributes ), types( types ) { 23 for ( Type * t : *this ) {24 // xxx - this is very awkward. TupleTypes should contain objects so that members can be named, but if they don't have an initializer node then25 // they end up getting constructors, which end up being inserted causing problems. This happens because the object decls have to be visited so that26 // their types are kept in sync with the types list here. Ultimately, the types list here should be eliminated and perhaps replaced with a list-view27 // of the object types list, but I digress. The temporary solution here is to make a ListInit with maybeConstructed = false, that way even when the28 // object is visited, it is never constructed. Ultimately, a better solution might be either:29 // a) to separate TupleType from its declarations, into TupleDecl and Tuple{Inst?}Type, ala StructDecl and StructInstType30 // b) separate initializer nodes better, e.g. add a MaybeConstructed node that is replaced by genInit, rather than what currently exists in a bool31 members.push_back( new ObjectDecl( "" , Type::StorageClasses(), LinkageSpec::Cforall, nullptr, t->clone(), new ListInit( {}, {}, false ) ) );32 }33 20 } 34 21 35 22 TupleType::TupleType( const TupleType& other ) : Type( other ) { 36 23 cloneAll( other.types, types ); 37 cloneAll( other.members, members );38 24 } 39 25 40 26 TupleType::~TupleType() { 41 27 deleteAll( types ); 42 deleteAll( members );43 28 } 44 29 -
src/SynTree/Type.h
r67fa9f9 r11dbfe1 481 481 class TupleType : public Type { 482 482 public: 483 TupleType( const Type::Qualifiers & tq, const std::list< Type * > & types , const std::list< Attribute * > & attributes = std::list< Attribute * >() );483 TupleType( const Type::Qualifiers & tq, const std::list< Type * > & types = std::list< Type * >(), const std::list< Attribute * > & attributes = std::list< Attribute * >() ); 484 484 TupleType( const TupleType& ); 485 485 virtual ~TupleType(); … … 488 488 typedef value_type::iterator iterator; 489 489 490 std::list<Type *>& get_types() { return types; }490 std::list<Type*>& get_types() { return types; } 491 491 virtual unsigned size() const { return types.size(); }; 492 493 // For now, this is entirely synthetic -- tuple types always have unnamed members.494 // Eventually, we may allow named tuples, in which case members should subsume types495 std::list<Declaration *> & get_members() { return members; }496 492 497 493 iterator begin() { return types.begin(); } … … 510 506 virtual void print( std::ostream & os, int indent = 0 ) const; 511 507 private: 512 std::list<Type *> types; 513 std::list<Declaration *> members; 508 std::list<Type*> types; 514 509 }; 515 510 -
src/SynTree/VarExprReplacer.cc
r67fa9f9 r11dbfe1 14 14 // 15 15 16 #include "Declaration.h"17 16 #include "Expression.h" 18 17 #include "VarExprReplacer.h" 19 18 20 VarExprReplacer::VarExprReplacer( const DeclMap & declMap , bool debug ) : declMap( declMap ), debug( debug) {}19 VarExprReplacer::VarExprReplacer( const DeclMap & declMap ) : declMap( declMap ) {} 21 20 22 21 // replace variable with new node from decl map 23 22 void VarExprReplacer::visit( VariableExpr * varExpr ) { 24 // xxx - assertions and parameters aren't accounted for in this... (i.e. they aren't inserted into the map when it's made, only DeclStmts are) 25 if ( declMap.count( varExpr->get_var() ) ) { 26 if ( debug ) { 27 std::cerr << "replacing variable reference: " << (void*)varExpr->get_var() << " " << varExpr->get_var() << " with " << (void*)declMap.at( varExpr->get_var() ) << " " << declMap.at( varExpr->get_var() ) << std::endl; 28 } 29 varExpr->set_var( declMap.at( varExpr->get_var() ) ); 30 } 23 // xxx - assertions and parameters aren't accounted for in this... (i.e. they aren't inserted into the map when it's made, only DeclStmts are) 24 if ( declMap.count( varExpr->get_var() ) ) { 25 varExpr->set_var( declMap.at( varExpr->get_var() ) ); 26 } 31 27 } -
src/SynTree/VarExprReplacer.h
r67fa9f9 r11dbfe1 27 27 private: 28 28 const DeclMap & declMap; 29 bool debug;30 29 public: 31 VarExprReplacer( const DeclMap & declMap , bool debug = false);30 VarExprReplacer( const DeclMap & declMap ); 32 31 33 32 // replace variable with new node from decl map -
src/SynTree/Visitor.cc
r67fa9f9 r11dbfe1 340 340 } 341 341 342 void Visitor::visit( UntypedInitExpr * initExpr ) {343 maybeAccept( initExpr->get_result(), *this );344 maybeAccept( initExpr->get_expr(), *this );345 // not currently visiting initAlts, but this doesn't matter since this node is only used in the resolver.346 }347 348 void Visitor::visit( InitExpr * initExpr ) {349 maybeAccept( initExpr->get_result(), *this );350 maybeAccept( initExpr->get_expr(), *this );351 maybeAccept( initExpr->get_designation(), *this );352 }353 354 342 355 343 void Visitor::visit( VoidType *voidType ) { … … 407 395 acceptAll( tupleType->get_forall(), *this ); 408 396 acceptAll( tupleType->get_types(), *this ); 409 acceptAll( tupleType->get_members(), *this );410 397 } 411 398 … … 437 424 } 438 425 439 void Visitor::visit( Designation * designation ) {440 acceptAll( designation->get_designators(), *this );441 }442 426 443 427 void Visitor::visit( SingleInit *singleInit ) { … … 446 430 447 431 void Visitor::visit( ListInit *listInit ) { 448 acceptAll( listInit->get_designat ions(), *this );432 acceptAll( listInit->get_designators(), *this ); 449 433 acceptAll( listInit->get_initializers(), *this ); 450 434 } -
src/SynTree/Visitor.h
r67fa9f9 r11dbfe1 88 88 virtual void visit( StmtExpr * stmtExpr ); 89 89 virtual void visit( UniqueExpr * uniqueExpr ); 90 virtual void visit( UntypedInitExpr * initExpr );91 virtual void visit( InitExpr * initExpr );92 90 93 91 virtual void visit( VoidType *basicType ); … … 108 106 virtual void visit( OneType *oneType ); 109 107 110 virtual void visit( Designation *designation );111 108 virtual void visit( SingleInit *singleInit ); 112 109 virtual void visit( ListInit *listInit ); -
src/Tuples/TupleExpansion.cc
r67fa9f9 r11dbfe1 192 192 } 193 193 ObjectDecl * finished = new ObjectDecl( toString( "_unq", id, "_finished_" ), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new BasicType( Type::Qualifiers(), BasicType::Bool ), 194 new SingleInit( new ConstantExpr( Constant::from_int( 0 ) ) ) );194 new SingleInit( new ConstantExpr( Constant::from_int( 0 ) ), noDesignators ) ); 195 195 addDeclaration( finished ); 196 196 // (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N)) … … 310 310 Type * makeTupleType( const std::list< Expression * > & exprs ) { 311 311 // produce the TupleType which aggregates the types of the exprs 312 std::list< Type * > types;313 Type::Qualifiers qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Lvalue | Type::Atomic | Type::Mutex);312 TupleType *tupleType = new TupleType( Type::Qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Lvalue | Type::Atomic | Type::Mutex ) ); 313 Type::Qualifiers &qualifiers = tupleType->get_qualifiers(); 314 314 for ( Expression * expr : exprs ) { 315 315 assert( expr->get_result() ); 316 316 if ( expr->get_result()->isVoid() ) { 317 317 // if the type of any expr is void, the type of the entire tuple is void 318 delete tupleType; 318 319 return new VoidType( Type::Qualifiers() ); 319 320 } 320 321 Type * type = expr->get_result()->clone(); 321 t ypes.push_back( type );322 tupleType->get_types().push_back( type ); 322 323 // the qualifiers on the tuple type are the qualifiers that exist on all component types 323 324 qualifiers &= type->get_qualifiers(); 324 325 } // for 325 326 if ( exprs.empty() ) qualifiers = Type::Qualifiers(); 326 return new TupleType( qualifiers, types );327 return tupleType; 327 328 } 328 329 -
src/libcfa/Makefile.am
r67fa9f9 r11dbfe1 50 50 51 51 libobjs = ${headers:=.o} 52 libsrc = libcfa-prelude.c interpose.c libhdr/libdebug.c ${headers:=.c} exception.c52 libsrc = libcfa-prelude.c interpose.c libhdr/libdebug.c ${headers:=.c} 53 53 54 54 # not all platforms support concurrency, add option do disable it -
src/libcfa/Makefile.in
r67fa9f9 r11dbfe1 102 102 containers/pair.c containers/result.c containers/vector.c \ 103 103 concurrency/coroutine.c concurrency/thread.c \ 104 concurrency/kernel.c concurrency/monitor.c exception.c\104 concurrency/kernel.c concurrency/monitor.c \ 105 105 concurrency/CtxSwitch-@MACHINE_TYPE@.S concurrency/alarm.c \ 106 106 concurrency/invoke.c concurrency/preemption.c … … 126 126 libcfa_d_a-interpose.$(OBJEXT) \ 127 127 libhdr/libcfa_d_a-libdebug.$(OBJEXT) $(am__objects_2) \ 128 libcfa_d_a-exception.$(OBJEXT)$(am__objects_3)128 $(am__objects_3) 129 129 am_libcfa_d_a_OBJECTS = $(am__objects_4) 130 130 libcfa_d_a_OBJECTS = $(am_libcfa_d_a_OBJECTS) … … 136 136 containers/pair.c containers/result.c containers/vector.c \ 137 137 concurrency/coroutine.c concurrency/thread.c \ 138 concurrency/kernel.c concurrency/monitor.c exception.c\138 concurrency/kernel.c concurrency/monitor.c \ 139 139 concurrency/CtxSwitch-@MACHINE_TYPE@.S concurrency/alarm.c \ 140 140 concurrency/invoke.c concurrency/preemption.c … … 158 158 libcfa_a-interpose.$(OBJEXT) \ 159 159 libhdr/libcfa_a-libdebug.$(OBJEXT) $(am__objects_6) \ 160 libcfa_a-exception.$(OBJEXT)$(am__objects_7)160 $(am__objects_7) 161 161 am_libcfa_a_OBJECTS = $(am__objects_8) 162 162 libcfa_a_OBJECTS = $(am_libcfa_a_OBJECTS) … … 328 328 libobjs = ${headers:=.o} 329 329 libsrc = libcfa-prelude.c interpose.c libhdr/libdebug.c ${headers:=.c} \ 330 exception.c$(am__append_4)330 $(am__append_4) 331 331 libcfa_a_SOURCES = ${libsrc} 332 332 libcfa_a_CFLAGS = -nodebug -O2 … … 514 514 515 515 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcfa_a-assert.Po@am__quote@ 516 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcfa_a-exception.Po@am__quote@517 516 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcfa_a-fstream.Po@am__quote@ 518 517 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcfa_a-interpose.Po@am__quote@ … … 525 524 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcfa_a-stdlib.Po@am__quote@ 526 525 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcfa_d_a-assert.Po@am__quote@ 527 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcfa_d_a-exception.Po@am__quote@528 526 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcfa_d_a-fstream.Po@am__quote@ 529 527 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcfa_d_a-interpose.Po@am__quote@ … … 852 850 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_d_a_CFLAGS) $(CFLAGS) -c -o concurrency/libcfa_d_a-monitor.obj `if test -f 'concurrency/monitor.c'; then $(CYGPATH_W) 'concurrency/monitor.c'; else $(CYGPATH_W) '$(srcdir)/concurrency/monitor.c'; fi` 853 851 854 libcfa_d_a-exception.obj: exception.c855 @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_d_a_CFLAGS) $(CFLAGS) -MT libcfa_d_a-exception.obj -MD -MP -MF $(DEPDIR)/libcfa_d_a-exception.Tpo -c -o libcfa_d_a-exception.obj `if test -f 'exception.c'; then $(CYGPATH_W) 'exception.c'; else $(CYGPATH_W) '$(srcdir)/exception.c'; fi`856 @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcfa_d_a-exception.Tpo $(DEPDIR)/libcfa_d_a-exception.Po857 @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exception.c' object='libcfa_d_a-exception.obj' libtool=no @AMDEPBACKSLASH@858 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@859 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_d_a_CFLAGS) $(CFLAGS) -c -o libcfa_d_a-exception.obj `if test -f 'exception.c'; then $(CYGPATH_W) 'exception.c'; else $(CYGPATH_W) '$(srcdir)/exception.c'; fi`860 861 852 concurrency/libcfa_d_a-alarm.o: concurrency/alarm.c 862 853 @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_d_a_CFLAGS) $(CFLAGS) -MT concurrency/libcfa_d_a-alarm.o -MD -MP -MF concurrency/$(DEPDIR)/libcfa_d_a-alarm.Tpo -c -o concurrency/libcfa_d_a-alarm.o `test -f 'concurrency/alarm.c' || echo '$(srcdir)/'`concurrency/alarm.c … … 1152 1143 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 1153 1144 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_a_CFLAGS) $(CFLAGS) -c -o concurrency/libcfa_a-monitor.obj `if test -f 'concurrency/monitor.c'; then $(CYGPATH_W) 'concurrency/monitor.c'; else $(CYGPATH_W) '$(srcdir)/concurrency/monitor.c'; fi` 1154 1155 libcfa_a-exception.obj: exception.c1156 @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_a_CFLAGS) $(CFLAGS) -MT libcfa_a-exception.obj -MD -MP -MF $(DEPDIR)/libcfa_a-exception.Tpo -c -o libcfa_a-exception.obj `if test -f 'exception.c'; then $(CYGPATH_W) 'exception.c'; else $(CYGPATH_W) '$(srcdir)/exception.c'; fi`1157 @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcfa_a-exception.Tpo $(DEPDIR)/libcfa_a-exception.Po1158 @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exception.c' object='libcfa_a-exception.obj' libtool=no @AMDEPBACKSLASH@1159 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@1160 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_a_CFLAGS) $(CFLAGS) -c -o libcfa_a-exception.obj `if test -f 'exception.c'; then $(CYGPATH_W) 'exception.c'; else $(CYGPATH_W) '$(srcdir)/exception.c'; fi`1161 1145 1162 1146 concurrency/libcfa_a-alarm.o: concurrency/alarm.c -
src/libcfa/exception.c
r67fa9f9 r11dbfe1 44 44 // RESUMPTION ================================================================ 45 45 46 void __cfaehm__throw_resum ption(exception *except) {47 48 // DEBUG 49 printf("Throwing resumption exception %d\n", *except);50 51 struct __ cfaehm__try_resume_node * original_head = shared_stack.current_resume;52 struct __ cfaehm__try_resume_node * current =46 void __cfaehm__throw_resume(exception except) { 47 48 // DEBUG 49 printf("Throwing resumption exception %d\n", except); 50 51 struct __try_resume_node * original_head = shared_stack.current_resume; 52 struct __try_resume_node * current = 53 53 (original_head) ? original_head->next : shared_stack.top_resume; 54 54 55 55 for ( ; current ; current = current->next) { 56 56 shared_stack.current_resume = current; 57 if (current-> handler(except)) {57 if (current->try_to_handle(except)) { 58 58 shared_stack.current_resume = original_head; 59 59 return; … … 61 61 } 62 62 63 printf("Unhandled exception %d\n", *except);63 printf("Unhandled exception %d\n", except); 64 64 shared_stack.current_resume = original_head; 65 65 66 66 // Fall back to termination: 67 __cfaehm__throw_terminat ion(except);67 __cfaehm__throw_terminate(except); 68 68 // TODO: Default handler for resumption. 69 69 } … … 73 73 * after the node is built but before it is made the top node. 74 74 */ 75 void __ cfaehm__try_resume_setup(struct __cfaehm__try_resume_node * node,76 int (*handler)(exception *except)) {75 void __try_resume_setup(struct __try_resume_node * node, 76 bool (*handler)(exception except)) { 77 77 node->next = shared_stack.top_resume; 78 node-> handler= handler;78 node->try_to_handle = handler; 79 79 shared_stack.top_resume = node; 80 80 } 81 81 82 void __ cfaehm__try_resume_cleanup(struct __cfaehm__try_resume_node * node) {82 void __try_resume_cleanup(struct __try_resume_node * node) { 83 83 shared_stack.top_resume = node->next; 84 84 } … … 111 111 } 112 112 113 void __cfaehm__throw_terminat ion( exception *val ) {113 void __cfaehm__throw_terminate( int val ) { 114 114 // Store the current exception 115 shared_stack.current_exception = *val;116 117 // DEBUG 118 printf("Throwing termination exception %d\n", *val);115 shared_stack.current_exception = val; 116 117 // DEBUG 118 printf("Throwing termination exception %d\n", val); 119 119 120 120 // Call stdlibc to raise the exception … … 147 147 148 148 // Nesting this the other way would probably be faster. 149 void __cfaehm__rethrow_terminat ion(void) {149 void __cfaehm__rethrow_terminate(void) { 150 150 // DEBUG 151 151 printf("Rethrowing termination exception\n"); 152 152 153 __cfaehm__throw_terminat ion(&shared_stack.current_exception);153 __cfaehm__throw_terminate(shared_stack.current_exception); 154 154 } 155 155 … … 322 322 // for details 323 323 __attribute__((noinline)) 324 void __ cfaehm__try_terminate(void (*try_block)(),325 void (*catch_block)(int index, exception *except),326 __attribute__((unused)) int (*match_block)(exception *except)) {324 void __try_terminate(void (*try_block)(), 325 void (*catch_block)(int index, exception except), 326 __attribute__((unused)) int (*match_block)(exception except)) { 327 327 //! volatile int xy = 0; 328 328 //! printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy); … … 364 364 // Exception handler 365 365 catch_block(shared_stack.current_handler_index, 366 &shared_stack.current_exception);366 shared_stack.current_exception); 367 367 } 368 368 … … 384 384 // Body uses language specific data and therefore could be modified arbitrarily 385 385 ".LLSDACSBCFA2:\n" // BODY start 386 " .uleb128 .TRYSTART-__ cfaehm__try_terminate\n" // Handled area start (relative to start of function)386 " .uleb128 .TRYSTART-__try_terminate\n" // Handled area start (relative to start of function) 387 387 " .uleb128 .TRYEND-.TRYSTART\n" // Handled area length 388 " .uleb128 .CATCH-__ cfaehm__try_terminate\n" // Hanlder landing pad adress (relative to start of function)388 " .uleb128 .CATCH-__try_terminate\n" // Hanlder landing pad adress (relative to start of function) 389 389 " .uleb128 1\n" // Action code, gcc seems to use always 0 390 390 ".LLSDACSECFA2:\n" // BODY end 391 391 " .text\n" // TABLE footer 392 " .size __ cfaehm__try_terminate, .-__cfaehm__try_terminate\n"392 " .size __try_terminate, .-__try_terminate\n" 393 393 " .ident \"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n" 394 394 // " .section .note.GNU-stack,\"x\",@progbits\n" -
src/libcfa/exception.h
r67fa9f9 r11dbfe1 38 38 // Data structure creates a list of resume handlers. 39 39 struct __cfaehm__try_resume_node { 40 struct__cfaehm__try_resume_node * next;40 __cfaehm__try_resume_node * next; 41 41 int (*handler)(exception * except); 42 42 }; 43 43 44 44 void __cfaehm__try_resume_setup( 45 struct__cfaehm__try_resume_node * node,45 __cfaehm__try_resume_node * node, 46 46 int (*handler)(exception * except)); 47 47 void __cfaehm__try_resume_cleanup( 48 struct__cfaehm__try_resume_node * node);48 __cfaehm__try_resume_node * node); 49 49 50 50 // Check for a standard way to call fake deconstructors. -
src/libcfa/fstream
r67fa9f9 r11dbfe1 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jul 1 16:37:53201713 // Update Count : 1 1212 // Last Modified On : Mon May 15 18:11:09 2017 13 // Update Count : 104 14 14 // 15 15 … … 24 24 _Bool sepDefault; 25 25 _Bool sepOnOff; 26 _Bool lastSepOn;27 26 const char * sepCur; 28 27 char separator[separateSize]; … … 36 35 const char * sepGetCur( ofstream * ); 37 36 void sepSetCur( ofstream *, const char * ); 38 _Bool lastSepOn( ofstream * );39 37 40 38 // public -
src/libcfa/fstream.c
r67fa9f9 r11dbfe1 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jul 1 16:37:54201713 // Update Count : 2 4212 // Last Modified On : Mon May 15 18:11:11 2017 13 // Update Count : 234 14 14 // 15 15 … … 33 33 this->sepDefault = sepDefault; 34 34 this->sepOnOff = sepOnOff; 35 this->lastSepOn = false;36 35 sepSet( this, separator ); 37 36 sepSetCur( this, sepGet( this ) ); … … 40 39 41 40 // private 42 _Bool lastSepOn( ofstream * os ) { return os->lastSepOn; } 43 _Bool sepPrt( ofstream * os ) { os->lastSepOn = false; return os->sepOnOff; } 41 _Bool sepPrt( ofstream * os ) { return os->sepOnOff; } 44 42 void sepReset( ofstream * os ) { os->sepOnOff = os->sepDefault; } 45 43 void sepReset( ofstream * os, _Bool reset ) { os->sepDefault = reset; os->sepOnOff = os->sepDefault; } … … 48 46 49 47 // public 50 void sepOn( ofstream * os ) { os-> lastSepOn = true; os->sepOnOff = true; }51 void sepOff( ofstream * os ) { os-> lastSepOn = false; os->sepOnOff = 0; }48 void sepOn( ofstream * os ) { os->sepOnOff = 1; } 49 void sepOff( ofstream * os ) { os->sepOnOff = 0; } 52 50 53 51 _Bool sepDisable( ofstream *os ) { 54 52 _Bool temp = os->sepDefault; 55 53 os->sepDefault = false; 56 os->lastSepOn = false;57 54 sepReset( os ); 58 55 return temp; … … 95 92 exit( EXIT_FAILURE ); 96 93 } // if 97 ?{}( os, file, true, false, " ", ", " );94 ?{}( os, file, 1, 0, " ", ", " ); 98 95 } // open 99 96 … … 135 132 } // fmt 136 133 137 static ofstream soutFile = { (FILE *)(&_IO_2_1_stdout_), true, false, " ", ", " };134 static ofstream soutFile = { (FILE *)(&_IO_2_1_stdout_), 1, 0, " ", ", " }; 138 135 ofstream *sout = &soutFile; 139 static ofstream serrFile = { (FILE *)(&_IO_2_1_stderr_), true, false, " ", ", " };136 static ofstream serrFile = { (FILE *)(&_IO_2_1_stderr_), 1, 0, " ", ", " }; 140 137 ofstream *serr = &serrFile; 141 138 -
src/libcfa/iostream
r67fa9f9 r11dbfe1 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Jul 2 08:42:56201713 // Update Count : 1 1012 // Last Modified On : Mon May 15 18:08:44 2017 13 // Update Count : 105 14 14 // 15 15 … … 26 26 const char * sepGetCur( ostype * ); // get current separator string 27 27 void sepSetCur( ostype *, const char * ); // set current separator string 28 _Bool lastSepOn( ostype * ); // last manipulator is setOn (context sensitive)29 28 // public 30 29 void sepOn( ostype * ); // turn separator state on … … 44 43 ostype * write( ostype *, const char *, unsigned long int ); 45 44 int fmt( ostype *, const char fmt[], ... ); 46 }; // ostream45 }; 47 46 48 47 trait writeable( otype T ) { 49 48 forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype *, T ); 50 }; // writeable49 }; 51 50 52 51 // implement writable for intrinsic types … … 104 103 istype * ungetc( istype *, char ); 105 104 int fmt( istype *, const char fmt[], ... ); 106 }; // istream105 }; 107 106 108 107 trait readable( otype T ) { 109 108 forall( dtype istype | istream( istype ) ) istype * ?|?( istype *, T ); 110 }; // readable109 }; 111 110 112 111 forall( dtype istype | istream( istype ) ) istype * ?|?( istype *, char * ); -
src/libcfa/iostream.c
r67fa9f9 r11dbfe1 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Jul 2 08:54:02201713 // Update Count : 3 7512 // Last Modified On : Mon May 8 18:24:23 2017 13 // Update Count : 369 14 14 // 15 15 … … 201 201 forall( dtype ostype, otype T, ttype Params | ostream( ostype ) | writeable( T ) | { ostype * ?|?( ostype *, Params ); } ) 202 202 ostype * ?|?( ostype * os, T arg, Params rest ) { 203 sepSetCur( os, sepGetTuple( os ) ); // switch to tuple separator 203 204 os | arg; // print first argument 204 sepSetCur( os, sepGetTuple( os ) ); // switch to tuple separator205 205 os | rest; // print remaining arguments 206 206 sepSetCur( os, sepGet( os ) ); // switch to regular separator … … 217 217 forall( dtype ostype | ostream( ostype ) ) 218 218 ostype * endl( ostype * os ) { 219 if ( lastSepOn( os ) ) fmt( os, "%s", sepGetCur( os ) );220 219 os | '\n'; 221 220 flush( os ); -
src/main.cc
r67fa9f9 r11dbfe1 11 11 // Created On : Fri May 15 23:12:02 2015 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Thu Jun 29 12:46:50201714 // Update Count : 44 113 // Last Modified On : Wed Jun 28 21:56:47 2017 14 // Update Count : 440 15 15 // 16 16 … … 39 39 #include "CodeTools/TrackLoc.h" 40 40 #include "ControlStruct/Mutate.h" 41 #include "ControlStruct/ExceptTranslate.h"42 41 #include "SymTab/Validate.h" 43 42 #include "ResolvExpr/AlternativePrinter.h" … … 291 290 Tuples::expandUniqueExpr( translationUnit ); 292 291 293 OPTPRINT( "translateEHM" );294 ControlStruct::translateEHM( translationUnit );295 296 292 OPTPRINT( "convertSpecializations" ) // needs to happen before tuple types are expanded 297 293 GenPoly::convertSpecializations( translationUnit ); … … 485 481 break; 486 482 case '?': 487 if ( optopt ) { // short option ? 488 assertf( false, "Unknown option: -%c\n", (char)optopt ); 489 } else { 490 assertf( false, "Unknown option: %s\n", argv[optind - 1] ); 491 } // if 483 assertf( false, "Unknown option: '%c'\n", (char)optopt ); 492 484 default: 493 485 abort(); -
src/prelude/Makefile.am
r67fa9f9 r11dbfe1 23 23 noinst_DATA = ../libcfa/libcfa-prelude.c 24 24 25 CC = ${abs_top_srcdir}/src/driver/cfa26 27 25 $(DEPDIR) : 28 26 mkdir $(DEPDIR) … … 47 45 48 46 # create forward declarations for cfa builtins 49 builtins.cf : builtins.c ${CC}50 ${AM_V_GEN} ${CC}-E -P ${<} -o ${@} -MD -MP -MF $(DEPDIR)/builtins.Po47 builtins.cf : builtins.c 48 ${AM_V_GEN}@BACKEND_CC@ -E -P ${<} -o ${@} -MD -MP -MF $(DEPDIR)/builtins.Po 51 49 ${AM_V_at}sed -i 's/builtins.o/builtins.cf/g' $(DEPDIR)/builtins.Po 52 50 -
src/prelude/Makefile.in
r67fa9f9 r11dbfe1 95 95 AWK = @AWK@ 96 96 BACKEND_CC = @BACKEND_CC@ 97 CC = ${abs_top_srcdir}/src/driver/cfa97 CC = @CC@ 98 98 CCAS = @CCAS@ 99 99 CCASDEPMODE = @CCASDEPMODE@ … … 444 444 445 445 # create forward declarations for cfa builtins 446 builtins.cf : builtins.c ${CC}447 ${AM_V_GEN} ${CC}-E -P ${<} -o ${@} -MD -MP -MF $(DEPDIR)/builtins.Po446 builtins.cf : builtins.c 447 ${AM_V_GEN}@BACKEND_CC@ -E -P ${<} -o ${@} -MD -MP -MF $(DEPDIR)/builtins.Po 448 448 ${AM_V_at}sed -i 's/builtins.o/builtins.cf/g' $(DEPDIR)/builtins.Po 449 449 -
src/tests/.expect/io.txt
r67fa9f9 r11dbfe1 4 4 123 5 5 6 opening delimiters7 6 x (1 x [2 x {3 x =4 x $5 x £6 x ¥7 x ¡8 x ¿9 x «10 8 9 closing delimiters 10 1, x 2. x 3; x 4! x 5? x 6% x 7¢ x 8» x 9) x 10] x 11} x 11 12 opening/closing delimiters 7 1, x 2. x 3; x 4! x 5? x 6% x 7¢ x 8» x 9) x 10] x 11} x 13 8 x`1`x'2'x"3"x:4:x 5 x 6 x 14 9 7 … … 19 14 x 20 15 10 21 x 22 23 override opening/closing delimiters 16 x 24 17 x ( 1 ) x 2 , x 3 :x: 4 25 26 input bacis types27 28 output basic types29 18 A 30 19 1 2 3 4 5 6 7 8 … … 32 21 1.1+2.3i 1.1-2.3i 1.1-2.3i 33 22 34 tuples35 1, 2, 3 3, 4, 536 37 toggle separator38 23 1.11.21.3 39 24 1.1+2.3i1.1-2.3i1.1-2.3i 40 abcxyz 41 abcxyz 25 abcxyz 26 abcxyz 42 27 43 change separator44 from " "to " , $"45 28 1.1, $1.2, $1.3 46 29 1.1+2.3i, $1.1-2.3i, $1.1-2.3i 47 abc, $xyz, $ 48 1, 2, 3, $3, 4, 5 30 abc, $xyz 49 31 50 from ", $"to " " 51 1.1 1.2 1.3 52 1.1+2.3i 1.1-2.3i 1.1-2.3i 53 abc xyz 54 1, 2, 3 3, 4, 5 55 56 1 2 3 32 1, 2, 3, 4 33 1, $2, $3 ", $" 34 1 2 3 " " 35 1 2 3 57 36 12 3 58 1 2 359 1 2 360 1 2 361 62 37 123 63 38 1 23 64 39 1 2 3 65 123 66 1 2 3 67 123 68 1 2 3 69 70 1 2 3 3 4 5 " " 71 1, 2, 3 3, 4, 5 ", " 72 1, 2, 3 3, 4, 5 73 40 1 2 3 4 " " 41 1, 2, 3, 4 ", " 42 1, 2, 3, 4 74 43 3, 4, a, 7.2 75 44 3, 4, a, 7.2 76 45 3 4 a 7.2 77 46 3 4 a 7.234a7.23 4 a 7.2 78 3-4-a-7.2^3^4 ^3-4-a-7.247 3-4-a-7.2^3^4-3-4-a-7.2 -
src/tests/io.c
r67fa9f9 r11dbfe1 10 10 // Created On : Wed Mar 2 16:56:02 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Jul 2 09:40:58201713 // Update Count : 6812 // Last Modified On : Thu Jun 8 09:52:10 2017 13 // Update Count : 51 14 14 // 15 15 … … 42 42 sout | endl; 43 43 44 sout | "opening delimiters" | endl;45 44 sout 45 // opening delimiters 46 46 | "x (" | 1 47 47 | "x [" | 2 … … 54 54 | "x ¿" | 9 55 55 | "x «" | 10 56 | endl | endl; 57 58 sout | "closing delimiters" | endl; 56 | endl; 59 57 sout 58 // closing delimiters 60 59 | 1 | ", x" 61 60 | 2 | ". x" … … 69 68 | 10 | "] x" 70 69 | 11 | "} x" 71 | endl | endl; 72 73 sout | "opening/closing delimiters" | endl; 70 | endl; 74 71 sout 72 // opening-closing delimiters 75 73 | "x`" | 1 | "`x'" | 2 76 74 | "'x\"" | 3 | "\"x:" | 4 … … 78 76 | "\tx\f" | 7 | "\fx\v" | 8 79 77 | "\vx\n" | 9 | "\nx\r" | 10 80 | "\rx" 81 | endl | endl; 82 83 sout | "override opening/closing delimiters" | endl; 78 | "\rx" | 79 endl; 84 80 sout | "x ( " | 1 | " ) x" | 2 | " , x" | 3 | " :x: " | 4 | endl; 85 sout | endl;86 81 87 82 ifstream in; // create / open file 88 83 open( &in, "io.data", "r" ); 89 84 90 sout | "input bacis types" | endl;91 85 &in | &c // character 92 86 | &si | &usi | &i | &ui | &li | &uli | &lli | &ulli // integral … … 94 88 | &fc | &dc | &ldc // floating-point complex 95 89 | cstr( s1 ) | cstr( s2, size ); // C string, length unchecked and checked 96 sout | endl;97 90 98 sout | "output basic types" | endl;99 91 sout | c | ' ' | endl // character 100 92 | si | usi | i | ui | li | uli | lli | ulli | endl // integral … … 102 94 | fc | dc | ldc | endl; // complex 103 95 sout | endl; 104 105 sout | "tuples" | endl;106 [int, [ int, int ] ] t1 = [ 1, [ 2, 3 ] ], t2 = [ 3, [ 4, 5 ] ];107 sout | t1 | t2 | endl; // print tuple108 sout | endl;109 110 sout | "toggle separator" | endl;111 96 sout | f | "" | d | "" | ld | endl // floating point without separator 112 97 | sepDisable | fc | dc | ldc | sepEnable | endl // complex without separator … … 115 100 sout | endl; 116 101 117 sout | "change separator" | endl;118 sout | "from \" " | sepGet( sout ) | "\"";119 102 sepSet( sout, ", $" ); // change separator, maximum of 15 characters 120 sout | "to \" " | sepGet( sout ) | "\"" | endl;121 103 sout | f | d | ld | endl 122 104 | fc | dc | ldc | endl 123 | s1 | s2 | endl 124 | t1 | t2 | endl; // print tuple 125 sout | endl; 126 sout | "from \"" | sepGet( sout ) | "\""; 127 sepSet( sout, " " ); // restore separator 128 sout | "to \"" | sepGet( sout ) | "\"" | endl; 129 sout | f | d | ld | endl 130 | fc | dc | ldc | endl 131 | s1 | s2 | endl 132 | t1 | t2 | endl; // print tuple 105 | s1 | s2 | endl; 133 106 sout | endl; 134 107 135 sout | sepOn | 1 | 2 | 3 | sepOn | endl; // separator at start/end of line 108 [int, int] t1 = [1, 2], t2 = [3, 4]; 109 sout | t1 | t2 | endl; // print tuple 110 111 sepSet( sout, " " ); 112 sepSet( sout, ", $" ); // set separator from " " to ", $" 113 sout | 1 | 2 | 3 | " \"" | sepGet( sout ) | "\"" | endl; 114 sepSet( sout, " " ); // reset separator to " " 115 sout | 1 | 2 | 3 | " \"" | sepGet( sout ) | "\"" | endl; 116 117 sout | sepOn | 1 | 2 | 3 | sepOn | endl; // separator at start of line 136 118 sout | 1 | sepOff | 2 | 3 | endl; // locally turn off implicit separator 137 sout | sepOn | 1 | 2 | 3 | sepOn | sepOff | endl; // separator at start of line138 sout | 1 | 2 | 3 | endl | sepOn; // separator at start of next line139 sout | 1 | 2 | 3 | endl;140 sout | endl;141 119 142 120 sout | sepDisable | 1 | 2 | 3 | endl; // globally turn off implicit separation 143 121 sout | 1 | sepOn | 2 | 3 | endl; // locally turn on implicit separator 144 sout | sepEnable | 1 | 2 | 3 | endl | sepDisable; // globally turn on/off implicit separation 145 sout | 1 | 2 | 3 | endl | sepEnable; // globally turn on implicit separation 146 sout | 1 | 2 | 3 | sepOn | sepDisable | endl; // ignore seperate at end of line 147 sout | 1 | 2 | 3 | sepOn | sepEnable | endl; // separator at end of line 148 sout | 1 | 2 | 3 | endl; 149 sout | endl; 122 sout | sepEnable | 1 | 2 | 3 | endl; // globally turn on implicit separation 150 123 151 124 sepSetTuple( sout, " " ); // set tuple separator from ", " to " " … … 153 126 sepSetTuple( sout, ", " ); // reset tuple separator to ", " 154 127 sout | t1 | t2 | " \"" | sepGetTuple( sout ) | "\"" | endl; 128 155 129 sout | t1 | t2 | endl; // print tuple 156 sout | endl;157 130 158 131 [int, int, const char *, double] t3 = { 3, 4, "a", 7.2 }; -
tools/cfa.nanorc
r67fa9f9 r11dbfe1 2 2 ## WIP 3 3 4 syntax "cfa" "\.cfa" 4 syntax "cfa" "\.cfa$" 5 ## No magic 5 6 6 7 # Macros … … 18 19 # Control Flow Structures 19 20 color brightyellow "\<(if|else|while|do|for|switch|choose|case|default)\>" 20 color brightyellow "\<(try|catch(Resume)?|finally)\>"21 ##color brightyellow "\<(try|catch|catchResume|finally)\>" 21 22 22 23 # Control Flow Statements 23 color magenta "\<( goto|return|break|continue|fallthr(u|ough)|throw(Resume)?)\>"24 color magenta "\<(return|break|continue|fallthru|throw)\>" 24 25 25 26 # Operator Names … … 45 46 color brightmagenta "'\\(([0-3]?[0-7]{1,2}))'" "'\\x[0-9A-Fa-f]{1,2}'" 46 47 # Strings and Angle Strings 47 color yellow ""([^"]|\\")*"" "<[^[:blank:]=]*>"48 color brightyellow ""([^"]|\\")*"" "<[^[:blank:]=]*>" 48 49 # Multiline Strings: This regex is VERY expencive and often too strong. 49 50 ###color brightyellow start=""(\\.|[^"])*\\[[:space:]]*$" end="^(\\.|[^"])*"" -
tools/prettyprinter/main.cc
r67fa9f9 r11dbfe1 1 1 // 2 // Cforall Version 1.0.0 Copyright (C) 201 7University of Waterloo2 // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo 3 3 // 4 4 // The contents of this file are covered under the licence agreement in the … … 10 10 // Created On : Wed Jun 28 22:57:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jun 29 13:09:32201713 // Update Count : 5812 // Last Modified On : Thu Jun 29 09:02:37 2017 13 // Update Count : 15 14 14 // 15 15 … … 19 19 using namespace std; 20 20 #include <unistd.h> // close 21 #include <getopt.h> // getopt22 21 #include "filter.h" 23 22 24 23 extern FILE * yyin; 24 extern int yylineno; 25 25 extern int yydebug; 26 26 extern int yyparse( void ); 27 27 28 bool parse_cmdline( int argc, char * argv[] ) {29 enum { Html, Identity, Latex, Nocode, ParseTree, };30 31 static struct option long_opts[] = {32 { "html", no_argument, nullptr, Html },33 { "identity", no_argument, nullptr, Identity },34 { "latex", no_argument, nullptr, Latex },35 { "nocode", no_argument, nullptr, Nocode },36 { "parse-tree", no_argument, nullptr, ParseTree },37 { nullptr, 0, nullptr, 0 }38 }; // long_opts39 int long_index;40 41 opterr = 0; // (global) prevent getopt from printing error messages42 43 int c;44 while ( (c = getopt_long( argc, argv, "hilnp", long_opts, &long_index )) != -1 ) {45 switch ( c ) {46 case Html:47 case 'h':48 filter = HTML;49 break;50 case Identity:51 case 'i':52 filter = ::Identity;53 break;54 case Latex:55 case 'l':56 filter = LaTeX;57 break;58 case Nocode:59 case 'n':60 filter = ::Nocode;61 break;62 case ParseTree:63 case 'p':64 filter = Parse_Tree;65 case '?':66 if ( optopt ) { // short option ?67 cerr << "Unknown option: -" << (char)optopt << endl;68 } else { // long option69 cerr << "Unknown option: " << argv[optind - 1] << endl;70 } // if71 return false;72 default:73 abort();74 } // switch75 } // while76 77 if ( optind != argc ) { // input files ?78 if ( optind == argc - 1 ) { // any commands after the flags ? => input file name79 yyin = fopen( argv[ optind ], "r" );80 if ( yyin == nullptr ) {81 cerr << "Open failure for input file \"" << argv[ optind ] << "\"" << endl;82 return false;83 } // if84 } else {85 cerr << "Too many input files " << argv[ optind + 1 ] << endl;86 return false;87 } // if88 } // if89 return true;90 } // parse_cmdline91 92 28 int main( int argc, char *argv[] ) { 93 yyin = stdin; // defaults29 yyin = stdin; 94 30 filter = Nocode; 95 31 96 if ( ! parse_cmdline( argc, argv ) ) { 97 cerr << "Usage: " << argv[0] 98 << " [" 99 << "-h/--html | " 100 << "-i/--identity | " 101 << "-l/--latex | " 102 << "-n/--nocode | " 103 << "-p/--parse-tree" 32 try { 33 switch ( argc ) { 34 case 3: 35 yyin = fopen( argv[ 2 ], "r" ); 36 if ( yyin == nullptr ) { 37 throw ios_base::failure( "unknown printer option arguments" ); 38 } // if 39 // FALL THROUGH 40 case 2: { 41 string arg( argv[1] ); 42 43 if ( arg == "-identity" ) { 44 filter = Identity; 45 } else if ( arg == "-parse_tree" ) { 46 filter = Parse_Tree; 47 } else if ( arg == "-nocode" ) { 48 filter = Nocode; 49 } else if ( arg == "-latex" ) { 50 filter = LaTeX; 51 } else if ( arg == "-html" ) { 52 filter = HTML; 53 } else { 54 throw ios_base::failure( "unknown printer option arguments" ); 55 } // if 56 break; 57 } 58 default: 59 throw ios_base::failure( "wrong number of arguments" ); 60 } // switch 61 } catch( ios_base::failure err ) { 62 cerr << err.what() << endl; 63 cerr << "Usage: [" << argv[0] 64 << "-identity |" 65 << "-parse_tree |" 66 << "-nocode |" 67 << "-latex |" 68 << "-html" 104 69 << "] [input-file]" 105 70 << endl; 106 71 exit( EXIT_FAILURE ); // TERMINATE 107 } // if72 } // try 108 73 109 74 //yydebug = 1;
Note:
See TracChangeset
for help on using the changeset viewer.