├── .gitignore ├── LICENSE ├── README.md ├── scripts ├── (<|>) ├── choice ├── desugar ├── eof ├── isAlpha ├── isAlphaNum ├── isNum ├── isSpace ├── many ├── match ├── notSpace ├── parens ├── replace ├── rmSpaces ├── satisfy ├── some ├── space └── spaces └── sigbovik2015 ├── IEEEtran.bst ├── IEEEtran.cls ├── bib.bib ├── paper.pdf ├── paper.tex └── sigplanconf.cls /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Mike Izbicki 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the {organization} nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # parsed 2 | 3 | Parsed (pronounced par-séd) is a suite of shell scripts to simplify parsing from the Unix shell. 4 | It improves the classic sed program by incorporating ideas from Haskell's popular [parsec](https://hackage.haskell.org/package/parsec) library. 5 | In particular, the Unix pipe operator `|` corresponds exactly to Haskell's Applicative bind `*>`. 6 | The resulting syntax is both intuitive and powerful. 7 | The original syntax used by sed can match only regular languages; 8 | but our improved syntax can match any context sensitive language. 9 | 10 | For example, the following one liner creates a parser for matching balanced parenthesis. 11 | ``` 12 | $ parens() { choice "$1" "match '(' | parens \"$1\" | match ')'"; } 13 | ``` 14 | For more examples and a detailed tutorial, please see our [SIGBOVIK2015 paper](https://github.com/mikeizbicki/parsed/raw/master/sigbovik2015/paper.pdf). 15 | -------------------------------------------------------------------------------- /scripts/(<|>): -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # We need to store the contents of stdin explicitly to a file. When we call one of our candidate parsers, it will consume some of the input form stdin. We need to restore that input before calling the next parser. 4 | stdin=$(tempfile) 5 | cat >"$stdin" 6 | 7 | # For similar reasons, we'll need to store the output of our parsers. 8 | stdout=$(tempfile) 9 | stderr=$(tempfile) 10 | 11 | # For each parser passed in as a command line arg 12 | for cmd in "$@"; do 13 | 14 | # Run the parser; if it succeeds, then pass on its results 15 | if $(eval "$cmd" <"$stdin" 1>"$stdout" 2>"$stderr") ; then 16 | cat "$stderr" >&2 17 | cat "$stdout" 18 | exit 0 19 | 20 | # Our parser failed and consumed input, so we fail 21 | elif [ ! -z "$stderr" ]; then 22 | exit 2 23 | fi 24 | done 25 | 26 | # All parsers failed, so we failed 27 | exit 1 28 | 29 | -------------------------------------------------------------------------------- /scripts/choice: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # We need to store the contents of stdin explicitly to a file. When we call one of our candidate parsers, it will consume some of the input form stdin. We need to restore that input before calling the next parser. 4 | stdin=$(tempfile) 5 | cat >"$stdin" 6 | 7 | # For similar reasons, we'll need to store the output of our parsers. 8 | stdout=$(tempfile) 9 | stderr=$(tempfile) 10 | 11 | # For each parser passed in as a command line arg 12 | for cmd in "$@"; do 13 | 14 | # Run the parser; if it succeeds, then pass on its results 15 | if $(eval "$cmd" <"$stdin" 1>"$stdout" 2>"$stderr") ; then 16 | cat "$stderr" >&2 17 | cat "$stdout" 18 | exit 0 19 | fi 20 | done 21 | 22 | # All parsers failed, so we failed 23 | exit 1 24 | -------------------------------------------------------------------------------- /scripts/desugar: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function parenStatement { 4 | match "(" | spaces | statement | spaces | match ")" 5 | } 6 | 7 | function statement { 8 | choice parenStatement "parenStatement | statement" 9 | } 10 | 11 | statement 12 | -------------------------------------------------------------------------------- /scripts/eof: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Try to read a single character into the variable $next. If next is empty, we're at the end of file, so parsing succeeds. 4 | IFS= 5 | read -n 1 next 6 | if [ -z $next ]; then exit 0; else exit 1; fi 7 | 8 | -------------------------------------------------------------------------------- /scripts/isAlpha: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | out=$(grep -e "[[:alpha:]]" <<< "$1") 4 | 5 | [ ${#out} -eq 1 ] && exit 0 6 | exit 1 7 | -------------------------------------------------------------------------------- /scripts/isAlphaNum: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | isAlpha $1 || isNum $1 4 | -------------------------------------------------------------------------------- /scripts/isNum: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | out=$(grep -e "[[:digit:]]" <<< "$1") 4 | 5 | [ ${#out} -eq 1 ] && exit 0 6 | exit 1 7 | 8 | -------------------------------------------------------------------------------- /scripts/isSpace: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | t=$(echo -e '\t') 4 | n=$(echo -e '\n') 5 | r=$(echo -e '\r') 6 | 7 | if [ ! -z "$1" ]; then 8 | [ "$1" = " " ] || [ "$1" = "$t" ] || [ "$1" = "$n" ] || [ "$1" = "$r" ] 9 | else 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /scripts/many: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -o pipefail 3 | $1 | some "$1" 4 | exit $? 5 | -------------------------------------------------------------------------------- /scripts/match: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # check for the correct number of arguments 4 | if [ -z "$1" ] || [ ! -z "$2" ]; then 5 | echo "match requires exactly one argument" 6 | exit 255 7 | fi 8 | 9 | # When reading from stdin, the shell ignores the contents of the IFS variable. By default, this is set to whitespace. In order to be able to read whitespace, we must set IFS to nothing. 10 | IFS='' 11 | 12 | # read in exactly as some characters as are in the first command line argument 13 | read -rn "${#1}" in 14 | 15 | # if we parse correctly 16 | if [ "$1" = "$in" ]; then 17 | # print the parsed string to stderr 18 | echo -n "$in" 1>&2 19 | 20 | # forward the unparsed contents of stdin 21 | cat 22 | 23 | # signal that parsing succeeded 24 | exit 0 25 | 26 | else 27 | # parsing failed 28 | exit 1 29 | fi 30 | 31 | -------------------------------------------------------------------------------- /scripts/notSpace: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | satisfy "! isSpace" 3 | -------------------------------------------------------------------------------- /scripts/parens: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | choice "$1" "match '(' | parens \"$1\" | match ')'" 3 | -------------------------------------------------------------------------------- /scripts/replace: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$1" ] || [ -z "$2" ] || [ ! -z "$3" ]; then 4 | echo "replace requires exactly two arguments" 5 | exit 255 6 | fi 7 | 8 | IFS= 9 | 10 | stdout=$(eval "$1" 2> /dev/null) 11 | #stdin=$(cat) 12 | #stdout=$(eval "$1" <<< "$stdin" 2> /dev/null) 13 | #eval "$1" 2>/dev/null 14 | 15 | if [ 0 -eq $? ]; then 16 | echo -n "<$2>" 1>&2 17 | echo -n "$stdout" 18 | exit 0 19 | fi 20 | 21 | exit 1 22 | -------------------------------------------------------------------------------- /scripts/rmSpaces: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | stdout=$(replace spaces " " | many notSpace) 4 | 5 | if [ ! -z "$stdout" ]; then 6 | rmSpaces <<< "$stdout" 7 | fi 8 | -------------------------------------------------------------------------------- /scripts/satisfy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$1" ] || [ ! -z "$2" ]; then 4 | echo "satisfy requires exactly one argument" 5 | exit 255 6 | fi 7 | 8 | IFS= 9 | read -rn 1 in 10 | 11 | #echo "in=[$in]" 12 | in=$(echo $in | sed -e "s/\\\\/\\\\\\\\/g" | sed -e "s/\"/\\\\\"/g") 13 | #echo "in=[$in]" 14 | 15 | if eval "$1 \"$in\""; then 16 | echo -n "$in" 1>&2 17 | cat 18 | exit 0 19 | fi 20 | exit 1 21 | -------------------------------------------------------------------------------- /scripts/some: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # check for the correct number of arguments 4 | if [ -z "$1" ] || [ ! -z "$2" ]; then 5 | echo "many requires exactly one argument" 6 | exit 255 7 | fi 8 | 9 | # put the contents of stdin into a variable so we can check if it's empty 10 | stdin=$(cat) 11 | 12 | # if we still have input and parsing succeeded 13 | if [ ! -z "$stdin" ] && stdout=`eval "$1" <<< "$stdin"`; then 14 | 15 | # run this parser again 16 | "$0" "$1" <<< "$stdout" 17 | else 18 | 19 | # stop running this parser 20 | cat <<< "$stdin" 21 | fi 22 | -------------------------------------------------------------------------------- /scripts/space: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | satisfy isSpace 3 | -------------------------------------------------------------------------------- /scripts/spaces: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | replace "many space" " " 3 | -------------------------------------------------------------------------------- /sigbovik2015/IEEEtran.bst: -------------------------------------------------------------------------------- 1 | %% 2 | %% IEEEtran.bst 3 | %% BibTeX Bibliography Style file for IEEE Journals and Conferences (unsorted) 4 | %% Version 1.12 (2007/01/11) 5 | %% 6 | %% Copyright (c) 2003-2007 Michael Shell 7 | %% 8 | %% Original starting code base and algorithms obtained from the output of 9 | %% Patrick W. Daly's makebst package as well as from prior versions of 10 | %% IEEE BibTeX styles: 11 | %% 12 | %% 1. Howard Trickey and Oren Patashnik's ieeetr.bst (1985/1988) 13 | %% 2. Silvano Balemi and Richard H. Roy's IEEEbib.bst (1993) 14 | %% 15 | %% Support sites: 16 | %% http://www.michaelshell.org/tex/ieeetran/ 17 | %% http://www.ctan.org/tex-archive/macros/latex/contrib/IEEEtran/ 18 | %% and/or 19 | %% http://www.ieee.org/ 20 | %% 21 | %% For use with BibTeX version 0.99a or later 22 | %% 23 | %% This is a numerical citation style. 24 | %% 25 | %%************************************************************************* 26 | %% Legal Notice: 27 | %% This code is offered as-is without any warranty either expressed or 28 | %% implied; without even the implied warranty of MERCHANTABILITY or 29 | %% FITNESS FOR A PARTICULAR PURPOSE! 30 | %% User assumes all risk. 31 | %% In no event shall IEEE or any contributor to this code be liable for 32 | %% any damages or losses, including, but not limited to, incidental, 33 | %% consequential, or any other damages, resulting from the use or misuse 34 | %% of any information contained here. 35 | %% 36 | %% All comments are the opinions of their respective authors and are not 37 | %% necessarily endorsed by the IEEE. 38 | %% 39 | %% This work is distributed under the LaTeX Project Public License (LPPL) 40 | %% ( http://www.latex-project.org/ ) version 1.3, and may be freely used, 41 | %% distributed and modified. A copy of the LPPL, version 1.3, is included 42 | %% in the base LaTeX documentation of all distributions of LaTeX released 43 | %% 2003/12/01 or later. 44 | %% Retain all contribution notices and credits. 45 | %% ** Modified files should be clearly indicated as such, including ** 46 | %% ** renaming them and changing author support contact information. ** 47 | %% 48 | %% File list of work: IEEEabrv.bib, IEEEfull.bib, IEEEexample.bib, 49 | %% IEEEtran.bst, IEEEtranS.bst, IEEEtranSA.bst, 50 | %% IEEEtranN.bst, IEEEtranSN.bst, IEEEtran_bst_HOWTO.pdf 51 | %%************************************************************************* 52 | % 53 | % 54 | % Changelog: 55 | % 56 | % 1.00 (2002/08/13) Initial release 57 | % 58 | % 1.10 (2002/09/27) 59 | % 1. Corrected minor bug for improperly formed warning message when a 60 | % book was not given a title. Thanks to Ming Kin Lai for reporting this. 61 | % 2. Added support for CTLname_format_string and CTLname_latex_cmd fields 62 | % in the BST control entry type. 63 | % 64 | % 1.11 (2003/04/02) 65 | % 1. Fixed bug with URLs containing underscores when using url.sty. Thanks 66 | % to Ming Kin Lai for reporting this. 67 | % 68 | % 1.12 (2007/01/11) 69 | % 1. Fixed bug with unwanted comma before "et al." when an entry contained 70 | % more than two author names. Thanks to Pallav Gupta for reporting this. 71 | % 2. Fixed bug with anomalous closing quote in tech reports that have a 72 | % type, but without a number or address. Thanks to Mehrdad Mirreza for 73 | % reporting this. 74 | % 3. Use braces in \providecommand in begin.bib to better support 75 | % latex2html. TeX style length assignments OK with recent versions 76 | % of latex2html - 1.71 (2002/2/1) or later is strongly recommended. 77 | % Use of the language field still causes trouble with latex2html. 78 | % Thanks to Federico Beffa for reporting this. 79 | % 4. Added IEEEtran.bst ID and version comment string to .bbl output. 80 | % 5. Provide a \BIBdecl hook that allows the user to execute commands 81 | % just prior to the first entry. 82 | % 6. Use default urlstyle (is using url.sty) of "same" rather than rm to 83 | % better work with a wider variety of bibliography styles. 84 | % 7. Changed month abbreviations from Sept., July and June to Sep., Jul., 85 | % and Jun., respectively, as IEEE now does. Thanks to Moritz Borgmann 86 | % for reporting this. 87 | % 8. Control entry types should not be considered when calculating longest 88 | % label width. 89 | % 9. Added alias www for electronic/online. 90 | % 10. Added CTLname_url_prefix control entry type. 91 | 92 | 93 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 94 | %% DEFAULTS FOR THE CONTROLS OF THE BST STYLE %% 95 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 96 | 97 | % These are the defaults for the user adjustable controls. The values used 98 | % here can be overridden by the user via IEEEtranBSTCTL entry type. 99 | 100 | % NOTE: The recommended LaTeX command to invoke a control entry type is: 101 | % 102 | %\makeatletter 103 | %\def\bstctlcite{\@ifnextchar[{\@bstctlcite}{\@bstctlcite[@auxout]}} 104 | %\def\@bstctlcite[#1]#2{\@bsphack 105 | % \@for\@citeb:=#2\do{% 106 | % \edef\@citeb{\expandafter\@firstofone\@citeb}% 107 | % \if@filesw\immediate\write\csname #1\endcsname{\string\citation{\@citeb}}\fi}% 108 | % \@esphack} 109 | %\makeatother 110 | % 111 | % It is called at the start of the document, before the first \cite, like: 112 | % \bstctlcite{IEEEexample:BSTcontrol} 113 | % 114 | % IEEEtran.cls V1.6 and later does provide this command. 115 | 116 | 117 | 118 | % #0 turns off the display of the number for articles. 119 | % #1 enables 120 | FUNCTION {default.is.use.number.for.article} { #1 } 121 | 122 | 123 | % #0 turns off the display of the paper and type fields in @inproceedings. 124 | % #1 enables 125 | FUNCTION {default.is.use.paper} { #1 } 126 | 127 | 128 | % #0 turns off the forced use of "et al." 129 | % #1 enables 130 | FUNCTION {default.is.forced.et.al} { #0 } 131 | 132 | % The maximum number of names that can be present beyond which an "et al." 133 | % usage is forced. Be sure that num.names.shown.with.forced.et.al (below) 134 | % is not greater than this value! 135 | % Note: There are many instances of references in IEEE journals which have 136 | % a very large number of authors as well as instances in which "et al." is 137 | % used profusely. 138 | FUNCTION {default.max.num.names.before.forced.et.al} { #10 } 139 | 140 | % The number of names that will be shown with a forced "et al.". 141 | % Must be less than or equal to max.num.names.before.forced.et.al 142 | FUNCTION {default.num.names.shown.with.forced.et.al} { #1 } 143 | 144 | 145 | % #0 turns off the alternate interword spacing for entries with URLs. 146 | % #1 enables 147 | FUNCTION {default.is.use.alt.interword.spacing} { #1 } 148 | 149 | % If alternate interword spacing for entries with URLs is enabled, this is 150 | % the interword spacing stretch factor that will be used. For example, the 151 | % default "4" here means that the interword spacing in entries with URLs can 152 | % stretch to four times normal. Does not have to be an integer. Note that 153 | % the value specified here can be overridden by the user in their LaTeX 154 | % code via a command such as: 155 | % "\providecommand\BIBentryALTinterwordstretchfactor{1.5}" in addition to 156 | % that via the IEEEtranBSTCTL entry type. 157 | FUNCTION {default.ALTinterwordstretchfactor} { "4" } 158 | 159 | 160 | % #0 turns off the "dashification" of repeated (i.e., identical to those 161 | % of the previous entry) names. IEEE normally does this. 162 | % #1 enables 163 | FUNCTION {default.is.dash.repeated.names} { #1 } 164 | 165 | 166 | % The default name format control string. 167 | FUNCTION {default.name.format.string}{ "{f.~}{vv~}{ll}{, jj}" } 168 | 169 | 170 | % The default LaTeX font command for the names. 171 | FUNCTION {default.name.latex.cmd}{ "" } 172 | 173 | 174 | % The default URL prefix. 175 | FUNCTION {default.name.url.prefix}{ "[Online]. Available:" } 176 | 177 | 178 | % Other controls that cannot be accessed via IEEEtranBSTCTL entry type. 179 | 180 | % #0 turns off the terminal startup banner/completed message so as to 181 | % operate more quietly. 182 | % #1 enables 183 | FUNCTION {is.print.banners.to.terminal} { #1 } 184 | 185 | 186 | 187 | 188 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%% 189 | %% FILE VERSION AND BANNER %% 190 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%% 191 | 192 | FUNCTION{bst.file.version} { "1.12" } 193 | FUNCTION{bst.file.date} { "2007/01/11" } 194 | FUNCTION{bst.file.website} { "http://www.michaelshell.org/tex/ieeetran/bibtex/" } 195 | 196 | FUNCTION {banner.message} 197 | { is.print.banners.to.terminal 198 | { "-- IEEEtran.bst version" " " * bst.file.version * 199 | " (" * bst.file.date * ") " * "by Michael Shell." * 200 | top$ 201 | "-- " bst.file.website * 202 | top$ 203 | "-- See the " quote$ * "IEEEtran_bst_HOWTO.pdf" * quote$ * " manual for usage information." * 204 | top$ 205 | } 206 | { skip$ } 207 | if$ 208 | } 209 | 210 | FUNCTION {completed.message} 211 | { is.print.banners.to.terminal 212 | { "" 213 | top$ 214 | "Done." 215 | top$ 216 | } 217 | { skip$ } 218 | if$ 219 | } 220 | 221 | 222 | 223 | 224 | %%%%%%%%%%%%%%%%%%%%%% 225 | %% STRING CONSTANTS %% 226 | %%%%%%%%%%%%%%%%%%%%%% 227 | 228 | FUNCTION {bbl.and}{ "and" } 229 | FUNCTION {bbl.etal}{ "et~al." } 230 | FUNCTION {bbl.editors}{ "eds." } 231 | FUNCTION {bbl.editor}{ "ed." } 232 | FUNCTION {bbl.edition}{ "ed." } 233 | FUNCTION {bbl.volume}{ "vol." } 234 | FUNCTION {bbl.of}{ "of" } 235 | FUNCTION {bbl.number}{ "no." } 236 | FUNCTION {bbl.in}{ "in" } 237 | FUNCTION {bbl.pages}{ "pp." } 238 | FUNCTION {bbl.page}{ "p." } 239 | FUNCTION {bbl.chapter}{ "ch." } 240 | FUNCTION {bbl.paper}{ "paper" } 241 | FUNCTION {bbl.part}{ "pt." } 242 | FUNCTION {bbl.patent}{ "Patent" } 243 | FUNCTION {bbl.patentUS}{ "U.S." } 244 | FUNCTION {bbl.revision}{ "Rev." } 245 | FUNCTION {bbl.series}{ "ser." } 246 | FUNCTION {bbl.standard}{ "Std." } 247 | FUNCTION {bbl.techrep}{ "Tech. Rep." } 248 | FUNCTION {bbl.mthesis}{ "Master's thesis" } 249 | FUNCTION {bbl.phdthesis}{ "Ph.D. dissertation" } 250 | FUNCTION {bbl.st}{ "st" } 251 | FUNCTION {bbl.nd}{ "nd" } 252 | FUNCTION {bbl.rd}{ "rd" } 253 | FUNCTION {bbl.th}{ "th" } 254 | 255 | 256 | % This is the LaTeX spacer that is used when a larger than normal space 257 | % is called for (such as just before the address:publisher). 258 | FUNCTION {large.space} { "\hskip 1em plus 0.5em minus 0.4em\relax " } 259 | 260 | % The LaTeX code for dashes that are used to represent repeated names. 261 | % Note: Some older IEEE journals used something like 262 | % "\rule{0.275in}{0.5pt}\," which is fairly thick and runs right along 263 | % the baseline. However, IEEE now uses a thinner, above baseline, 264 | % six dash long sequence. 265 | FUNCTION {repeated.name.dashes} { "------" } 266 | 267 | 268 | 269 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 270 | %% PREDEFINED STRING MACROS %% 271 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 272 | 273 | MACRO {jan} {"Jan."} 274 | MACRO {feb} {"Feb."} 275 | MACRO {mar} {"Mar."} 276 | MACRO {apr} {"Apr."} 277 | MACRO {may} {"May"} 278 | MACRO {jun} {"Jun."} 279 | MACRO {jul} {"Jul."} 280 | MACRO {aug} {"Aug."} 281 | MACRO {sep} {"Sep."} 282 | MACRO {oct} {"Oct."} 283 | MACRO {nov} {"Nov."} 284 | MACRO {dec} {"Dec."} 285 | 286 | 287 | 288 | %%%%%%%%%%%%%%%%%% 289 | %% ENTRY FIELDS %% 290 | %%%%%%%%%%%%%%%%%% 291 | 292 | ENTRY 293 | { address 294 | assignee 295 | author 296 | booktitle 297 | chapter 298 | day 299 | dayfiled 300 | edition 301 | editor 302 | howpublished 303 | institution 304 | intype 305 | journal 306 | key 307 | language 308 | month 309 | monthfiled 310 | nationality 311 | note 312 | number 313 | organization 314 | pages 315 | paper 316 | publisher 317 | school 318 | series 319 | revision 320 | title 321 | type 322 | url 323 | volume 324 | year 325 | yearfiled 326 | CTLuse_article_number 327 | CTLuse_paper 328 | CTLuse_forced_etal 329 | CTLmax_names_forced_etal 330 | CTLnames_show_etal 331 | CTLuse_alt_spacing 332 | CTLalt_stretch_factor 333 | CTLdash_repeated_names 334 | CTLname_format_string 335 | CTLname_latex_cmd 336 | CTLname_url_prefix 337 | } 338 | {} 339 | { label } 340 | 341 | 342 | 343 | 344 | %%%%%%%%%%%%%%%%%%%%%%% 345 | %% INTEGER VARIABLES %% 346 | %%%%%%%%%%%%%%%%%%%%%%% 347 | 348 | INTEGERS { prev.status.punct this.status.punct punct.std 349 | punct.no punct.comma punct.period 350 | prev.status.space this.status.space space.std 351 | space.no space.normal space.large 352 | prev.status.quote this.status.quote quote.std 353 | quote.no quote.close 354 | prev.status.nline this.status.nline nline.std 355 | nline.no nline.newblock 356 | status.cap cap.std 357 | cap.no cap.yes} 358 | 359 | INTEGERS { longest.label.width multiresult nameptr namesleft number.label numnames } 360 | 361 | INTEGERS { is.use.number.for.article 362 | is.use.paper 363 | is.forced.et.al 364 | max.num.names.before.forced.et.al 365 | num.names.shown.with.forced.et.al 366 | is.use.alt.interword.spacing 367 | is.dash.repeated.names} 368 | 369 | 370 | %%%%%%%%%%%%%%%%%%%%%% 371 | %% STRING VARIABLES %% 372 | %%%%%%%%%%%%%%%%%%%%%% 373 | 374 | STRINGS { bibinfo 375 | longest.label 376 | oldname 377 | s 378 | t 379 | ALTinterwordstretchfactor 380 | name.format.string 381 | name.latex.cmd 382 | name.url.prefix} 383 | 384 | 385 | 386 | 387 | %%%%%%%%%%%%%%%%%%%%%%%%% 388 | %% LOW LEVEL FUNCTIONS %% 389 | %%%%%%%%%%%%%%%%%%%%%%%%% 390 | 391 | FUNCTION {initialize.controls} 392 | { default.is.use.number.for.article 'is.use.number.for.article := 393 | default.is.use.paper 'is.use.paper := 394 | default.is.forced.et.al 'is.forced.et.al := 395 | default.max.num.names.before.forced.et.al 'max.num.names.before.forced.et.al := 396 | default.num.names.shown.with.forced.et.al 'num.names.shown.with.forced.et.al := 397 | default.is.use.alt.interword.spacing 'is.use.alt.interword.spacing := 398 | default.is.dash.repeated.names 'is.dash.repeated.names := 399 | default.ALTinterwordstretchfactor 'ALTinterwordstretchfactor := 400 | default.name.format.string 'name.format.string := 401 | default.name.latex.cmd 'name.latex.cmd := 402 | default.name.url.prefix 'name.url.prefix := 403 | } 404 | 405 | 406 | % This IEEEtran.bst features a very powerful and flexible mechanism for 407 | % controlling the capitalization, punctuation, spacing, quotation, and 408 | % newlines of the formatted entry fields. (Note: IEEEtran.bst does not need 409 | % or use the newline/newblock feature, but it has been implemented for 410 | % possible future use.) The output states of IEEEtran.bst consist of 411 | % multiple independent attributes and, as such, can be thought of as being 412 | % vectors, rather than the simple scalar values ("before.all", 413 | % "mid.sentence", etc.) used in most other .bst files. 414 | % 415 | % The more flexible and complex design used here was motivated in part by 416 | % IEEE's rather unusual bibliography style. For example, IEEE ends the 417 | % previous field item with a period and large space prior to the publisher 418 | % address; the @electronic entry types use periods as inter-item punctuation 419 | % rather than the commas used by the other entry types; and URLs are never 420 | % followed by periods even though they are the last item in the entry. 421 | % Although it is possible to accommodate these features with the conventional 422 | % output state system, the seemingly endless exceptions make for convoluted, 423 | % unreliable and difficult to maintain code. 424 | % 425 | % IEEEtran.bst's output state system can be easily understood via a simple 426 | % illustration of two most recently formatted entry fields (on the stack): 427 | % 428 | % CURRENT_ITEM 429 | % "PREVIOUS_ITEM 430 | % 431 | % which, in this example, is to eventually appear in the bibliography as: 432 | % 433 | % "PREVIOUS_ITEM," CURRENT_ITEM 434 | % 435 | % It is the job of the output routine to take the previous item off of the 436 | % stack (while leaving the current item at the top of the stack), apply its 437 | % trailing punctuation (including closing quote marks) and spacing, and then 438 | % to write the result to BibTeX's output buffer: 439 | % 440 | % "PREVIOUS_ITEM," 441 | % 442 | % Punctuation (and spacing) between items is often determined by both of the 443 | % items rather than just the first one. The presence of quotation marks 444 | % further complicates the situation because, in standard English, trailing 445 | % punctuation marks are supposed to be contained within the quotes. 446 | % 447 | % IEEEtran.bst maintains two output state (aka "status") vectors which 448 | % correspond to the previous and current (aka "this") items. Each vector 449 | % consists of several independent attributes which track punctuation, 450 | % spacing, quotation, and newlines. Capitalization status is handled by a 451 | % separate scalar because the format routines, not the output routine, 452 | % handle capitalization and, therefore, there is no need to maintain the 453 | % capitalization attribute for both the "previous" and "this" items. 454 | % 455 | % When a format routine adds a new item, it copies the current output status 456 | % vector to the previous output status vector and (usually) resets the 457 | % current (this) output status vector to a "standard status" vector. Using a 458 | % "standard status" vector in this way allows us to redefine what we mean by 459 | % "standard status" at the start of each entry handler and reuse the same 460 | % format routines under the various inter-item separation schemes. For 461 | % example, the standard status vector for the @book entry type may use 462 | % commas for item separators, while the @electronic type may use periods, 463 | % yet both entry handlers exploit many of the exact same format routines. 464 | % 465 | % Because format routines have write access to the output status vector of 466 | % the previous item, they can override the punctuation choices of the 467 | % previous format routine! Therefore, it becomes trivial to implement rules 468 | % such as "Always use a period and a large space before the publisher." By 469 | % pushing the generation of the closing quote mark to the output routine, we 470 | % avoid all the problems caused by having to close a quote before having all 471 | % the information required to determine what the punctuation should be. 472 | % 473 | % The IEEEtran.bst output state system can easily be expanded if needed. 474 | % For instance, it is easy to add a "space.tie" attribute value if the 475 | % bibliography rules mandate that two items have to be joined with an 476 | % unbreakable space. 477 | 478 | FUNCTION {initialize.status.constants} 479 | { #0 'punct.no := 480 | #1 'punct.comma := 481 | #2 'punct.period := 482 | #0 'space.no := 483 | #1 'space.normal := 484 | #2 'space.large := 485 | #0 'quote.no := 486 | #1 'quote.close := 487 | #0 'cap.no := 488 | #1 'cap.yes := 489 | #0 'nline.no := 490 | #1 'nline.newblock := 491 | } 492 | 493 | FUNCTION {std.status.using.comma} 494 | { punct.comma 'punct.std := 495 | space.normal 'space.std := 496 | quote.no 'quote.std := 497 | nline.no 'nline.std := 498 | cap.no 'cap.std := 499 | } 500 | 501 | FUNCTION {std.status.using.period} 502 | { punct.period 'punct.std := 503 | space.normal 'space.std := 504 | quote.no 'quote.std := 505 | nline.no 'nline.std := 506 | cap.yes 'cap.std := 507 | } 508 | 509 | FUNCTION {initialize.prev.this.status} 510 | { punct.no 'prev.status.punct := 511 | space.no 'prev.status.space := 512 | quote.no 'prev.status.quote := 513 | nline.no 'prev.status.nline := 514 | punct.no 'this.status.punct := 515 | space.no 'this.status.space := 516 | quote.no 'this.status.quote := 517 | nline.no 'this.status.nline := 518 | cap.yes 'status.cap := 519 | } 520 | 521 | FUNCTION {this.status.std} 522 | { punct.std 'this.status.punct := 523 | space.std 'this.status.space := 524 | quote.std 'this.status.quote := 525 | nline.std 'this.status.nline := 526 | } 527 | 528 | FUNCTION {cap.status.std}{ cap.std 'status.cap := } 529 | 530 | FUNCTION {this.to.prev.status} 531 | { this.status.punct 'prev.status.punct := 532 | this.status.space 'prev.status.space := 533 | this.status.quote 'prev.status.quote := 534 | this.status.nline 'prev.status.nline := 535 | } 536 | 537 | 538 | FUNCTION {not} 539 | { { #0 } 540 | { #1 } 541 | if$ 542 | } 543 | 544 | FUNCTION {and} 545 | { { skip$ } 546 | { pop$ #0 } 547 | if$ 548 | } 549 | 550 | FUNCTION {or} 551 | { { pop$ #1 } 552 | { skip$ } 553 | if$ 554 | } 555 | 556 | 557 | % convert the strings "yes" or "no" to #1 or #0 respectively 558 | FUNCTION {yes.no.to.int} 559 | { "l" change.case$ duplicate$ 560 | "yes" = 561 | { pop$ #1 } 562 | { duplicate$ "no" = 563 | { pop$ #0 } 564 | { "unknown boolean " quote$ * swap$ * quote$ * 565 | " in " * cite$ * warning$ 566 | #0 567 | } 568 | if$ 569 | } 570 | if$ 571 | } 572 | 573 | 574 | % pushes true if the single char string on the stack is in the 575 | % range of "0" to "9" 576 | FUNCTION {is.num} 577 | { chr.to.int$ 578 | duplicate$ "0" chr.to.int$ < not 579 | swap$ "9" chr.to.int$ > not and 580 | } 581 | 582 | % multiplies the integer on the stack by a factor of 10 583 | FUNCTION {bump.int.mag} 584 | { #0 'multiresult := 585 | { duplicate$ #0 > } 586 | { #1 - 587 | multiresult #10 + 588 | 'multiresult := 589 | } 590 | while$ 591 | pop$ 592 | multiresult 593 | } 594 | 595 | % converts a single character string on the stack to an integer 596 | FUNCTION {char.to.integer} 597 | { duplicate$ 598 | is.num 599 | { chr.to.int$ "0" chr.to.int$ - } 600 | {"noninteger character " quote$ * swap$ * quote$ * 601 | " in integer field of " * cite$ * warning$ 602 | #0 603 | } 604 | if$ 605 | } 606 | 607 | % converts a string on the stack to an integer 608 | FUNCTION {string.to.integer} 609 | { duplicate$ text.length$ 'namesleft := 610 | #1 'nameptr := 611 | #0 'numnames := 612 | { nameptr namesleft > not } 613 | { duplicate$ nameptr #1 substring$ 614 | char.to.integer numnames bump.int.mag + 615 | 'numnames := 616 | nameptr #1 + 617 | 'nameptr := 618 | } 619 | while$ 620 | pop$ 621 | numnames 622 | } 623 | 624 | 625 | 626 | 627 | % The output routines write out the *next* to the top (previous) item on the 628 | % stack, adding punctuation and such as needed. Since IEEEtran.bst maintains 629 | % the output status for the top two items on the stack, these output 630 | % routines have to consider the previous output status (which corresponds to 631 | % the item that is being output). Full independent control of punctuation, 632 | % closing quote marks, spacing, and newblock is provided. 633 | % 634 | % "output.nonnull" does not check for the presence of a previous empty 635 | % item. 636 | % 637 | % "output" does check for the presence of a previous empty item and will 638 | % remove an empty item rather than outputing it. 639 | % 640 | % "output.warn" is like "output", but will issue a warning if it detects 641 | % an empty item. 642 | 643 | FUNCTION {output.nonnull} 644 | { swap$ 645 | prev.status.punct punct.comma = 646 | { "," * } 647 | { skip$ } 648 | if$ 649 | prev.status.punct punct.period = 650 | { add.period$ } 651 | { skip$ } 652 | if$ 653 | prev.status.quote quote.close = 654 | { "''" * } 655 | { skip$ } 656 | if$ 657 | prev.status.space space.normal = 658 | { " " * } 659 | { skip$ } 660 | if$ 661 | prev.status.space space.large = 662 | { large.space * } 663 | { skip$ } 664 | if$ 665 | write$ 666 | prev.status.nline nline.newblock = 667 | { newline$ "\newblock " write$ } 668 | { skip$ } 669 | if$ 670 | } 671 | 672 | FUNCTION {output} 673 | { duplicate$ empty$ 674 | 'pop$ 675 | 'output.nonnull 676 | if$ 677 | } 678 | 679 | FUNCTION {output.warn} 680 | { 't := 681 | duplicate$ empty$ 682 | { pop$ "empty " t * " in " * cite$ * warning$ } 683 | 'output.nonnull 684 | if$ 685 | } 686 | 687 | % "fin.entry" is the output routine that handles the last item of the entry 688 | % (which will be on the top of the stack when "fin.entry" is called). 689 | 690 | FUNCTION {fin.entry} 691 | { this.status.punct punct.no = 692 | { skip$ } 693 | { add.period$ } 694 | if$ 695 | this.status.quote quote.close = 696 | { "''" * } 697 | { skip$ } 698 | if$ 699 | write$ 700 | newline$ 701 | } 702 | 703 | 704 | FUNCTION {is.last.char.not.punct} 705 | { duplicate$ 706 | "}" * add.period$ 707 | #-1 #1 substring$ "." = 708 | } 709 | 710 | FUNCTION {is.multiple.pages} 711 | { 't := 712 | #0 'multiresult := 713 | { multiresult not 714 | t empty$ not 715 | and 716 | } 717 | { t #1 #1 substring$ 718 | duplicate$ "-" = 719 | swap$ duplicate$ "," = 720 | swap$ "+" = 721 | or or 722 | { #1 'multiresult := } 723 | { t #2 global.max$ substring$ 't := } 724 | if$ 725 | } 726 | while$ 727 | multiresult 728 | } 729 | 730 | FUNCTION {capitalize}{ "u" change.case$ "t" change.case$ } 731 | 732 | FUNCTION {emphasize} 733 | { duplicate$ empty$ 734 | { pop$ "" } 735 | { "\emph{" swap$ * "}" * } 736 | if$ 737 | } 738 | 739 | FUNCTION {do.name.latex.cmd} 740 | { name.latex.cmd 741 | empty$ 742 | { skip$ } 743 | { name.latex.cmd "{" * swap$ * "}" * } 744 | if$ 745 | } 746 | 747 | % IEEEtran.bst uses its own \BIBforeignlanguage command which directly 748 | % invokes the TeX hyphenation patterns without the need of the Babel 749 | % package. Babel does a lot more than switch hyphenation patterns and 750 | % its loading can cause unintended effects in many class files (such as 751 | % IEEEtran.cls). 752 | FUNCTION {select.language} 753 | { duplicate$ empty$ 'pop$ 754 | { language empty$ 'skip$ 755 | { "\BIBforeignlanguage{" language * "}{" * swap$ * "}" * } 756 | if$ 757 | } 758 | if$ 759 | } 760 | 761 | FUNCTION {tie.or.space.prefix} 762 | { duplicate$ text.length$ #3 < 763 | { "~" } 764 | { " " } 765 | if$ 766 | swap$ 767 | } 768 | 769 | FUNCTION {get.bbl.editor} 770 | { editor num.names$ #1 > 'bbl.editors 'bbl.editor if$ } 771 | 772 | FUNCTION {space.word}{ " " swap$ * " " * } 773 | 774 | 775 | % Field Conditioners, Converters, Checkers and External Interfaces 776 | 777 | FUNCTION {empty.field.to.null.string} 778 | { duplicate$ empty$ 779 | { pop$ "" } 780 | { skip$ } 781 | if$ 782 | } 783 | 784 | FUNCTION {either.or.check} 785 | { empty$ 786 | { pop$ } 787 | { "can't use both " swap$ * " fields in " * cite$ * warning$ } 788 | if$ 789 | } 790 | 791 | FUNCTION {empty.entry.warn} 792 | { author empty$ title empty$ howpublished empty$ 793 | month empty$ year empty$ note empty$ url empty$ 794 | and and and and and and 795 | { "all relevant fields are empty in " cite$ * warning$ } 796 | 'skip$ 797 | if$ 798 | } 799 | 800 | 801 | % The bibinfo system provides a way for the electronic parsing/acquisition 802 | % of a bibliography's contents as is done by ReVTeX. For example, a field 803 | % could be entered into the bibliography as: 804 | % \bibinfo{volume}{2} 805 | % Only the "2" would show up in the document, but the LaTeX \bibinfo command 806 | % could do additional things with the information. IEEEtran.bst does provide 807 | % a \bibinfo command via "\providecommand{\bibinfo}[2]{#2}". However, it is 808 | % currently not used as the bogus bibinfo functions defined here output the 809 | % entry values directly without the \bibinfo wrapper. The bibinfo functions 810 | % themselves (and the calls to them) are retained for possible future use. 811 | % 812 | % bibinfo.check avoids acting on missing fields while bibinfo.warn will 813 | % issue a warning message if a missing field is detected. Prior to calling 814 | % the bibinfo functions, the user should push the field value and then its 815 | % name string, in that order. 816 | 817 | FUNCTION {bibinfo.check} 818 | { swap$ duplicate$ missing$ 819 | { pop$ pop$ "" } 820 | { duplicate$ empty$ 821 | { swap$ pop$ } 822 | { swap$ pop$ } 823 | if$ 824 | } 825 | if$ 826 | } 827 | 828 | FUNCTION {bibinfo.warn} 829 | { swap$ duplicate$ missing$ 830 | { swap$ "missing " swap$ * " in " * cite$ * warning$ pop$ "" } 831 | { duplicate$ empty$ 832 | { swap$ "empty " swap$ * " in " * cite$ * warning$ } 833 | { swap$ pop$ } 834 | if$ 835 | } 836 | if$ 837 | } 838 | 839 | 840 | % IEEE separates large numbers with more than 4 digits into groups of 841 | % three. IEEE uses a small space to separate these number groups. 842 | % Typical applications include patent and page numbers. 843 | 844 | % number of consecutive digits required to trigger the group separation. 845 | FUNCTION {large.number.trigger}{ #5 } 846 | 847 | % For numbers longer than the trigger, this is the blocksize of the groups. 848 | % The blocksize must be less than the trigger threshold, and 2 * blocksize 849 | % must be greater than the trigger threshold (can't do more than one 850 | % separation on the initial trigger). 851 | FUNCTION {large.number.blocksize}{ #3 } 852 | 853 | % What is actually inserted between the number groups. 854 | FUNCTION {large.number.separator}{ "\," } 855 | 856 | % So as to save on integer variables by reusing existing ones, numnames 857 | % holds the current number of consecutive digits read and nameptr holds 858 | % the number that will trigger an inserted space. 859 | FUNCTION {large.number.separate} 860 | { 't := 861 | "" 862 | #0 'numnames := 863 | large.number.trigger 'nameptr := 864 | { t empty$ not } 865 | { t #-1 #1 substring$ is.num 866 | { numnames #1 + 'numnames := } 867 | { #0 'numnames := 868 | large.number.trigger 'nameptr := 869 | } 870 | if$ 871 | t #-1 #1 substring$ swap$ * 872 | t #-2 global.max$ substring$ 't := 873 | numnames nameptr = 874 | { duplicate$ #1 nameptr large.number.blocksize - substring$ swap$ 875 | nameptr large.number.blocksize - #1 + global.max$ substring$ 876 | large.number.separator swap$ * * 877 | nameptr large.number.blocksize - 'numnames := 878 | large.number.blocksize #1 + 'nameptr := 879 | } 880 | { skip$ } 881 | if$ 882 | } 883 | while$ 884 | } 885 | 886 | % Converts all single dashes "-" to double dashes "--". 887 | FUNCTION {n.dashify} 888 | { large.number.separate 889 | 't := 890 | "" 891 | { t empty$ not } 892 | { t #1 #1 substring$ "-" = 893 | { t #1 #2 substring$ "--" = not 894 | { "--" * 895 | t #2 global.max$ substring$ 't := 896 | } 897 | { { t #1 #1 substring$ "-" = } 898 | { "-" * 899 | t #2 global.max$ substring$ 't := 900 | } 901 | while$ 902 | } 903 | if$ 904 | } 905 | { t #1 #1 substring$ * 906 | t #2 global.max$ substring$ 't := 907 | } 908 | if$ 909 | } 910 | while$ 911 | } 912 | 913 | 914 | % This function detects entries with names that are identical to that of 915 | % the previous entry and replaces the repeated names with dashes (if the 916 | % "is.dash.repeated.names" user control is nonzero). 917 | FUNCTION {name.or.dash} 918 | { 's := 919 | oldname empty$ 920 | { s 'oldname := s } 921 | { s oldname = 922 | { is.dash.repeated.names 923 | { repeated.name.dashes } 924 | { s 'oldname := s } 925 | if$ 926 | } 927 | { s 'oldname := s } 928 | if$ 929 | } 930 | if$ 931 | } 932 | 933 | % Converts the number string on the top of the stack to 934 | % "numerical ordinal form" (e.g., "7" to "7th"). There is 935 | % no artificial limit to the upper bound of the numbers as the 936 | % least significant digit always determines the ordinal form. 937 | FUNCTION {num.to.ordinal} 938 | { duplicate$ #-1 #1 substring$ "1" = 939 | { bbl.st * } 940 | { duplicate$ #-1 #1 substring$ "2" = 941 | { bbl.nd * } 942 | { duplicate$ #-1 #1 substring$ "3" = 943 | { bbl.rd * } 944 | { bbl.th * } 945 | if$ 946 | } 947 | if$ 948 | } 949 | if$ 950 | } 951 | 952 | % If the string on the top of the stack begins with a number, 953 | % (e.g., 11th) then replace the string with the leading number 954 | % it contains. Otherwise retain the string as-is. s holds the 955 | % extracted number, t holds the part of the string that remains 956 | % to be scanned. 957 | FUNCTION {extract.num} 958 | { duplicate$ 't := 959 | "" 's := 960 | { t empty$ not } 961 | { t #1 #1 substring$ 962 | t #2 global.max$ substring$ 't := 963 | duplicate$ is.num 964 | { s swap$ * 's := } 965 | { pop$ "" 't := } 966 | if$ 967 | } 968 | while$ 969 | s empty$ 970 | 'skip$ 971 | { pop$ s } 972 | if$ 973 | } 974 | 975 | % Converts the word number string on the top of the stack to 976 | % Arabic string form. Will be successful up to "tenth". 977 | FUNCTION {word.to.num} 978 | { duplicate$ "l" change.case$ 's := 979 | s "first" = 980 | { pop$ "1" } 981 | { skip$ } 982 | if$ 983 | s "second" = 984 | { pop$ "2" } 985 | { skip$ } 986 | if$ 987 | s "third" = 988 | { pop$ "3" } 989 | { skip$ } 990 | if$ 991 | s "fourth" = 992 | { pop$ "4" } 993 | { skip$ } 994 | if$ 995 | s "fifth" = 996 | { pop$ "5" } 997 | { skip$ } 998 | if$ 999 | s "sixth" = 1000 | { pop$ "6" } 1001 | { skip$ } 1002 | if$ 1003 | s "seventh" = 1004 | { pop$ "7" } 1005 | { skip$ } 1006 | if$ 1007 | s "eighth" = 1008 | { pop$ "8" } 1009 | { skip$ } 1010 | if$ 1011 | s "ninth" = 1012 | { pop$ "9" } 1013 | { skip$ } 1014 | if$ 1015 | s "tenth" = 1016 | { pop$ "10" } 1017 | { skip$ } 1018 | if$ 1019 | } 1020 | 1021 | 1022 | % Converts the string on the top of the stack to numerical 1023 | % ordinal (e.g., "11th") form. 1024 | FUNCTION {convert.edition} 1025 | { duplicate$ empty$ 'skip$ 1026 | { duplicate$ #1 #1 substring$ is.num 1027 | { extract.num 1028 | num.to.ordinal 1029 | } 1030 | { word.to.num 1031 | duplicate$ #1 #1 substring$ is.num 1032 | { num.to.ordinal } 1033 | { "edition ordinal word " quote$ * edition * quote$ * 1034 | " may be too high (or improper) for conversion" * " in " * cite$ * warning$ 1035 | } 1036 | if$ 1037 | } 1038 | if$ 1039 | } 1040 | if$ 1041 | } 1042 | 1043 | 1044 | 1045 | 1046 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1047 | %% LATEX BIBLIOGRAPHY CODE %% 1048 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1049 | 1050 | FUNCTION {start.entry} 1051 | { newline$ 1052 | "\bibitem{" write$ 1053 | cite$ write$ 1054 | "}" write$ 1055 | newline$ 1056 | "" 1057 | initialize.prev.this.status 1058 | } 1059 | 1060 | % Here we write out all the LaTeX code that we will need. The most involved 1061 | % code sequences are those that control the alternate interword spacing and 1062 | % foreign language hyphenation patterns. The heavy use of \providecommand 1063 | % gives users a way to override the defaults. Special thanks to Javier Bezos, 1064 | % Johannes Braams, Robin Fairbairns, Heiko Oberdiek, Donald Arseneau and all 1065 | % the other gurus on comp.text.tex for their help and advice on the topic of 1066 | % \selectlanguage, Babel and BibTeX. 1067 | FUNCTION {begin.bib} 1068 | { "% Generated by IEEEtran.bst, version: " bst.file.version * " (" * bst.file.date * ")" * 1069 | write$ newline$ 1070 | preamble$ empty$ 'skip$ 1071 | { preamble$ write$ newline$ } 1072 | if$ 1073 | "\begin{thebibliography}{" longest.label * "}" * 1074 | write$ newline$ 1075 | "\providecommand{\url}[1]{#1}" 1076 | write$ newline$ 1077 | "\csname url@samestyle\endcsname" 1078 | write$ newline$ 1079 | "\providecommand{\newblock}{\relax}" 1080 | write$ newline$ 1081 | "\providecommand{\bibinfo}[2]{#2}" 1082 | write$ newline$ 1083 | "\providecommand{\BIBentrySTDinterwordspacing}{\spaceskip=0pt\relax}" 1084 | write$ newline$ 1085 | "\providecommand{\BIBentryALTinterwordstretchfactor}{" 1086 | ALTinterwordstretchfactor * "}" * 1087 | write$ newline$ 1088 | "\providecommand{\BIBentryALTinterwordspacing}{\spaceskip=\fontdimen2\font plus " 1089 | write$ newline$ 1090 | "\BIBentryALTinterwordstretchfactor\fontdimen3\font minus \fontdimen4\font\relax}" 1091 | write$ newline$ 1092 | "\providecommand{\BIBforeignlanguage}[2]{{%" 1093 | write$ newline$ 1094 | "\expandafter\ifx\csname l@#1\endcsname\relax" 1095 | write$ newline$ 1096 | "\typeout{** WARNING: IEEEtran.bst: No hyphenation pattern has been}%" 1097 | write$ newline$ 1098 | "\typeout{** loaded for the language `#1'. Using the pattern for}%" 1099 | write$ newline$ 1100 | "\typeout{** the default language instead.}%" 1101 | write$ newline$ 1102 | "\else" 1103 | write$ newline$ 1104 | "\language=\csname l@#1\endcsname" 1105 | write$ newline$ 1106 | "\fi" 1107 | write$ newline$ 1108 | "#2}}" 1109 | write$ newline$ 1110 | "\providecommand{\BIBdecl}{\relax}" 1111 | write$ newline$ 1112 | "\BIBdecl" 1113 | write$ newline$ 1114 | } 1115 | 1116 | FUNCTION {end.bib} 1117 | { newline$ "\end{thebibliography}" write$ newline$ } 1118 | 1119 | FUNCTION {if.url.alt.interword.spacing} 1120 | { is.use.alt.interword.spacing 1121 | {url empty$ 'skip$ {"\BIBentryALTinterwordspacing" write$ newline$} if$} 1122 | { skip$ } 1123 | if$ 1124 | } 1125 | 1126 | FUNCTION {if.url.std.interword.spacing} 1127 | { is.use.alt.interword.spacing 1128 | {url empty$ 'skip$ {"\BIBentrySTDinterwordspacing" write$ newline$} if$} 1129 | { skip$ } 1130 | if$ 1131 | } 1132 | 1133 | 1134 | 1135 | 1136 | %%%%%%%%%%%%%%%%%%%%%%%% 1137 | %% LONGEST LABEL PASS %% 1138 | %%%%%%%%%%%%%%%%%%%%%%%% 1139 | 1140 | FUNCTION {initialize.longest.label} 1141 | { "" 'longest.label := 1142 | #1 'number.label := 1143 | #0 'longest.label.width := 1144 | } 1145 | 1146 | FUNCTION {longest.label.pass} 1147 | { type$ "ieeetranbstctl" = 1148 | { skip$ } 1149 | { number.label int.to.str$ 'label := 1150 | number.label #1 + 'number.label := 1151 | label width$ longest.label.width > 1152 | { label 'longest.label := 1153 | label width$ 'longest.label.width := 1154 | } 1155 | { skip$ } 1156 | if$ 1157 | } 1158 | if$ 1159 | } 1160 | 1161 | 1162 | 1163 | 1164 | %%%%%%%%%%%%%%%%%%%%% 1165 | %% FORMAT HANDLERS %% 1166 | %%%%%%%%%%%%%%%%%%%%% 1167 | 1168 | %% Lower Level Formats (used by higher level formats) 1169 | 1170 | FUNCTION {format.address.org.or.pub.date} 1171 | { 't := 1172 | "" 1173 | year empty$ 1174 | { "empty year in " cite$ * warning$ } 1175 | { skip$ } 1176 | if$ 1177 | address empty$ t empty$ and 1178 | year empty$ and month empty$ and 1179 | { skip$ } 1180 | { this.to.prev.status 1181 | this.status.std 1182 | cap.status.std 1183 | address "address" bibinfo.check * 1184 | t empty$ 1185 | { skip$ } 1186 | { punct.period 'prev.status.punct := 1187 | space.large 'prev.status.space := 1188 | address empty$ 1189 | { skip$ } 1190 | { ": " * } 1191 | if$ 1192 | t * 1193 | } 1194 | if$ 1195 | year empty$ month empty$ and 1196 | { skip$ } 1197 | { t empty$ address empty$ and 1198 | { skip$ } 1199 | { ", " * } 1200 | if$ 1201 | month empty$ 1202 | { year empty$ 1203 | { skip$ } 1204 | { year "year" bibinfo.check * } 1205 | if$ 1206 | } 1207 | { month "month" bibinfo.check * 1208 | year empty$ 1209 | { skip$ } 1210 | { " " * year "year" bibinfo.check * } 1211 | if$ 1212 | } 1213 | if$ 1214 | } 1215 | if$ 1216 | } 1217 | if$ 1218 | } 1219 | 1220 | 1221 | FUNCTION {format.names} 1222 | { 'bibinfo := 1223 | duplicate$ empty$ 'skip$ { 1224 | this.to.prev.status 1225 | this.status.std 1226 | 's := 1227 | "" 't := 1228 | #1 'nameptr := 1229 | s num.names$ 'numnames := 1230 | numnames 'namesleft := 1231 | { namesleft #0 > } 1232 | { s nameptr 1233 | name.format.string 1234 | format.name$ 1235 | bibinfo bibinfo.check 1236 | 't := 1237 | nameptr #1 > 1238 | { nameptr num.names.shown.with.forced.et.al #1 + = 1239 | numnames max.num.names.before.forced.et.al > 1240 | is.forced.et.al and and 1241 | { "others" 't := 1242 | #1 'namesleft := 1243 | } 1244 | { skip$ } 1245 | if$ 1246 | namesleft #1 > 1247 | { ", " * t do.name.latex.cmd * } 1248 | { s nameptr "{ll}" format.name$ duplicate$ "others" = 1249 | { 't := } 1250 | { pop$ } 1251 | if$ 1252 | t "others" = 1253 | { " " * bbl.etal emphasize * } 1254 | { numnames #2 > 1255 | { "," * } 1256 | { skip$ } 1257 | if$ 1258 | bbl.and 1259 | space.word * t do.name.latex.cmd * 1260 | } 1261 | if$ 1262 | } 1263 | if$ 1264 | } 1265 | { t do.name.latex.cmd } 1266 | if$ 1267 | nameptr #1 + 'nameptr := 1268 | namesleft #1 - 'namesleft := 1269 | } 1270 | while$ 1271 | cap.status.std 1272 | } if$ 1273 | } 1274 | 1275 | 1276 | 1277 | 1278 | %% Higher Level Formats 1279 | 1280 | %% addresses/locations 1281 | 1282 | FUNCTION {format.address} 1283 | { address duplicate$ empty$ 'skip$ 1284 | { this.to.prev.status 1285 | this.status.std 1286 | cap.status.std 1287 | } 1288 | if$ 1289 | } 1290 | 1291 | 1292 | 1293 | %% author/editor names 1294 | 1295 | FUNCTION {format.authors}{ author "author" format.names } 1296 | 1297 | FUNCTION {format.editors} 1298 | { editor "editor" format.names duplicate$ empty$ 'skip$ 1299 | { ", " * 1300 | get.bbl.editor 1301 | capitalize 1302 | * 1303 | } 1304 | if$ 1305 | } 1306 | 1307 | 1308 | 1309 | %% date 1310 | 1311 | FUNCTION {format.date} 1312 | { 1313 | month "month" bibinfo.check duplicate$ empty$ 1314 | year "year" bibinfo.check duplicate$ empty$ 1315 | { swap$ 'skip$ 1316 | { this.to.prev.status 1317 | this.status.std 1318 | cap.status.std 1319 | "there's a month but no year in " cite$ * warning$ } 1320 | if$ 1321 | * 1322 | } 1323 | { this.to.prev.status 1324 | this.status.std 1325 | cap.status.std 1326 | swap$ 'skip$ 1327 | { 1328 | swap$ 1329 | " " * swap$ 1330 | } 1331 | if$ 1332 | * 1333 | } 1334 | if$ 1335 | } 1336 | 1337 | FUNCTION {format.date.electronic} 1338 | { month "month" bibinfo.check duplicate$ empty$ 1339 | year "year" bibinfo.check duplicate$ empty$ 1340 | { swap$ 1341 | { pop$ } 1342 | { "there's a month but no year in " cite$ * warning$ 1343 | pop$ ")" * "(" swap$ * 1344 | this.to.prev.status 1345 | punct.no 'this.status.punct := 1346 | space.normal 'this.status.space := 1347 | quote.no 'this.status.quote := 1348 | cap.yes 'status.cap := 1349 | } 1350 | if$ 1351 | } 1352 | { swap$ 1353 | { swap$ pop$ ")" * "(" swap$ * } 1354 | { "(" swap$ * ", " * swap$ * ")" * } 1355 | if$ 1356 | this.to.prev.status 1357 | punct.no 'this.status.punct := 1358 | space.normal 'this.status.space := 1359 | quote.no 'this.status.quote := 1360 | cap.yes 'status.cap := 1361 | } 1362 | if$ 1363 | } 1364 | 1365 | 1366 | 1367 | %% edition/title 1368 | 1369 | % Note: IEEE considers the edition to be closely associated with 1370 | % the title of a book. So, in IEEEtran.bst the edition is normally handled 1371 | % within the formatting of the title. The format.edition function is 1372 | % retained here for possible future use. 1373 | FUNCTION {format.edition} 1374 | { edition duplicate$ empty$ 'skip$ 1375 | { this.to.prev.status 1376 | this.status.std 1377 | convert.edition 1378 | status.cap 1379 | { "t" } 1380 | { "l" } 1381 | if$ change.case$ 1382 | "edition" bibinfo.check 1383 | "~" * bbl.edition * 1384 | cap.status.std 1385 | } 1386 | if$ 1387 | } 1388 | 1389 | % This is used to format the booktitle of a conference proceedings. 1390 | % Here we use the "intype" field to provide the user a way to 1391 | % override the word "in" (e.g., with things like "presented at") 1392 | % Use of intype stops the emphasis of the booktitle to indicate that 1393 | % we no longer mean the written conference proceedings, but the 1394 | % conference itself. 1395 | FUNCTION {format.in.booktitle} 1396 | { booktitle "booktitle" bibinfo.check duplicate$ empty$ 'skip$ 1397 | { this.to.prev.status 1398 | this.status.std 1399 | select.language 1400 | intype missing$ 1401 | { emphasize 1402 | bbl.in " " * 1403 | } 1404 | { intype " " * } 1405 | if$ 1406 | swap$ * 1407 | cap.status.std 1408 | } 1409 | if$ 1410 | } 1411 | 1412 | % This is used to format the booktitle of collection. 1413 | % Here the "intype" field is not supported, but "edition" is. 1414 | FUNCTION {format.in.booktitle.edition} 1415 | { booktitle "booktitle" bibinfo.check duplicate$ empty$ 'skip$ 1416 | { this.to.prev.status 1417 | this.status.std 1418 | select.language 1419 | emphasize 1420 | edition empty$ 'skip$ 1421 | { ", " * 1422 | edition 1423 | convert.edition 1424 | "l" change.case$ 1425 | * "~" * bbl.edition * 1426 | } 1427 | if$ 1428 | bbl.in " " * swap$ * 1429 | cap.status.std 1430 | } 1431 | if$ 1432 | } 1433 | 1434 | FUNCTION {format.article.title} 1435 | { title duplicate$ empty$ 'skip$ 1436 | { this.to.prev.status 1437 | this.status.std 1438 | "t" change.case$ 1439 | } 1440 | if$ 1441 | "title" bibinfo.check 1442 | duplicate$ empty$ 'skip$ 1443 | { quote.close 'this.status.quote := 1444 | is.last.char.not.punct 1445 | { punct.std 'this.status.punct := } 1446 | { punct.no 'this.status.punct := } 1447 | if$ 1448 | select.language 1449 | "``" swap$ * 1450 | cap.status.std 1451 | } 1452 | if$ 1453 | } 1454 | 1455 | FUNCTION {format.article.title.electronic} 1456 | { title duplicate$ empty$ 'skip$ 1457 | { this.to.prev.status 1458 | this.status.std 1459 | cap.status.std 1460 | "t" change.case$ 1461 | } 1462 | if$ 1463 | "title" bibinfo.check 1464 | duplicate$ empty$ 1465 | { skip$ } 1466 | { select.language } 1467 | if$ 1468 | } 1469 | 1470 | FUNCTION {format.book.title.edition} 1471 | { title "title" bibinfo.check 1472 | duplicate$ empty$ 1473 | { "empty title in " cite$ * warning$ } 1474 | { this.to.prev.status 1475 | this.status.std 1476 | select.language 1477 | emphasize 1478 | edition empty$ 'skip$ 1479 | { ", " * 1480 | edition 1481 | convert.edition 1482 | status.cap 1483 | { "t" } 1484 | { "l" } 1485 | if$ 1486 | change.case$ 1487 | * "~" * bbl.edition * 1488 | } 1489 | if$ 1490 | cap.status.std 1491 | } 1492 | if$ 1493 | } 1494 | 1495 | FUNCTION {format.book.title} 1496 | { title "title" bibinfo.check 1497 | duplicate$ empty$ 'skip$ 1498 | { this.to.prev.status 1499 | this.status.std 1500 | cap.status.std 1501 | select.language 1502 | emphasize 1503 | } 1504 | if$ 1505 | } 1506 | 1507 | 1508 | 1509 | %% journal 1510 | 1511 | FUNCTION {format.journal} 1512 | { journal duplicate$ empty$ 'skip$ 1513 | { this.to.prev.status 1514 | this.status.std 1515 | cap.status.std 1516 | select.language 1517 | emphasize 1518 | } 1519 | if$ 1520 | } 1521 | 1522 | 1523 | 1524 | %% how published 1525 | 1526 | FUNCTION {format.howpublished} 1527 | { howpublished duplicate$ empty$ 'skip$ 1528 | { this.to.prev.status 1529 | this.status.std 1530 | cap.status.std 1531 | } 1532 | if$ 1533 | } 1534 | 1535 | 1536 | 1537 | %% institutions/organization/publishers/school 1538 | 1539 | FUNCTION {format.institution} 1540 | { institution duplicate$ empty$ 'skip$ 1541 | { this.to.prev.status 1542 | this.status.std 1543 | cap.status.std 1544 | } 1545 | if$ 1546 | } 1547 | 1548 | FUNCTION {format.organization} 1549 | { organization duplicate$ empty$ 'skip$ 1550 | { this.to.prev.status 1551 | this.status.std 1552 | cap.status.std 1553 | } 1554 | if$ 1555 | } 1556 | 1557 | FUNCTION {format.address.publisher.date} 1558 | { publisher "publisher" bibinfo.warn format.address.org.or.pub.date } 1559 | 1560 | FUNCTION {format.address.publisher.date.nowarn} 1561 | { publisher "publisher" bibinfo.check format.address.org.or.pub.date } 1562 | 1563 | FUNCTION {format.address.organization.date} 1564 | { organization "organization" bibinfo.check format.address.org.or.pub.date } 1565 | 1566 | FUNCTION {format.school} 1567 | { school duplicate$ empty$ 'skip$ 1568 | { this.to.prev.status 1569 | this.status.std 1570 | cap.status.std 1571 | } 1572 | if$ 1573 | } 1574 | 1575 | 1576 | 1577 | %% volume/number/series/chapter/pages 1578 | 1579 | FUNCTION {format.volume} 1580 | { volume empty.field.to.null.string 1581 | duplicate$ empty$ 'skip$ 1582 | { this.to.prev.status 1583 | this.status.std 1584 | bbl.volume 1585 | status.cap 1586 | { capitalize } 1587 | { skip$ } 1588 | if$ 1589 | swap$ tie.or.space.prefix 1590 | "volume" bibinfo.check 1591 | * * 1592 | cap.status.std 1593 | } 1594 | if$ 1595 | } 1596 | 1597 | FUNCTION {format.number} 1598 | { number empty.field.to.null.string 1599 | duplicate$ empty$ 'skip$ 1600 | { this.to.prev.status 1601 | this.status.std 1602 | status.cap 1603 | { bbl.number capitalize } 1604 | { bbl.number } 1605 | if$ 1606 | swap$ tie.or.space.prefix 1607 | "number" bibinfo.check 1608 | * * 1609 | cap.status.std 1610 | } 1611 | if$ 1612 | } 1613 | 1614 | FUNCTION {format.number.if.use.for.article} 1615 | { is.use.number.for.article 1616 | { format.number } 1617 | { "" } 1618 | if$ 1619 | } 1620 | 1621 | % IEEE does not seem to tie the series so closely with the volume 1622 | % and number as is done in other bibliography styles. Instead the 1623 | % series is treated somewhat like an extension of the title. 1624 | FUNCTION {format.series} 1625 | { series empty$ 1626 | { "" } 1627 | { this.to.prev.status 1628 | this.status.std 1629 | bbl.series " " * 1630 | series "series" bibinfo.check * 1631 | cap.status.std 1632 | } 1633 | if$ 1634 | } 1635 | 1636 | 1637 | FUNCTION {format.chapter} 1638 | { chapter empty$ 1639 | { "" } 1640 | { this.to.prev.status 1641 | this.status.std 1642 | type empty$ 1643 | { bbl.chapter } 1644 | { type "l" change.case$ 1645 | "type" bibinfo.check 1646 | } 1647 | if$ 1648 | chapter tie.or.space.prefix 1649 | "chapter" bibinfo.check 1650 | * * 1651 | cap.status.std 1652 | } 1653 | if$ 1654 | } 1655 | 1656 | 1657 | % The intended use of format.paper is for paper numbers of inproceedings. 1658 | % The paper type can be overridden via the type field. 1659 | % We allow the type to be displayed even if the paper number is absent 1660 | % for things like "postdeadline paper" 1661 | FUNCTION {format.paper} 1662 | { is.use.paper 1663 | { paper empty$ 1664 | { type empty$ 1665 | { "" } 1666 | { this.to.prev.status 1667 | this.status.std 1668 | type "type" bibinfo.check 1669 | cap.status.std 1670 | } 1671 | if$ 1672 | } 1673 | { this.to.prev.status 1674 | this.status.std 1675 | type empty$ 1676 | { bbl.paper } 1677 | { type "type" bibinfo.check } 1678 | if$ 1679 | " " * paper 1680 | "paper" bibinfo.check 1681 | * 1682 | cap.status.std 1683 | } 1684 | if$ 1685 | } 1686 | { "" } 1687 | if$ 1688 | } 1689 | 1690 | 1691 | FUNCTION {format.pages} 1692 | { pages duplicate$ empty$ 'skip$ 1693 | { this.to.prev.status 1694 | this.status.std 1695 | duplicate$ is.multiple.pages 1696 | { 1697 | bbl.pages swap$ 1698 | n.dashify 1699 | } 1700 | { 1701 | bbl.page swap$ 1702 | } 1703 | if$ 1704 | tie.or.space.prefix 1705 | "pages" bibinfo.check 1706 | * * 1707 | cap.status.std 1708 | } 1709 | if$ 1710 | } 1711 | 1712 | 1713 | 1714 | %% technical report number 1715 | 1716 | FUNCTION {format.tech.report.number} 1717 | { number "number" bibinfo.check 1718 | this.to.prev.status 1719 | this.status.std 1720 | cap.status.std 1721 | type duplicate$ empty$ 1722 | { pop$ 1723 | bbl.techrep 1724 | } 1725 | { skip$ } 1726 | if$ 1727 | "type" bibinfo.check 1728 | swap$ duplicate$ empty$ 1729 | { pop$ } 1730 | { tie.or.space.prefix * * } 1731 | if$ 1732 | } 1733 | 1734 | 1735 | 1736 | %% note 1737 | 1738 | FUNCTION {format.note} 1739 | { note empty$ 1740 | { "" } 1741 | { this.to.prev.status 1742 | this.status.std 1743 | punct.period 'this.status.punct := 1744 | note #1 #1 substring$ 1745 | duplicate$ "{" = 1746 | { skip$ } 1747 | { status.cap 1748 | { "u" } 1749 | { "l" } 1750 | if$ 1751 | change.case$ 1752 | } 1753 | if$ 1754 | note #2 global.max$ substring$ * "note" bibinfo.check 1755 | cap.yes 'status.cap := 1756 | } 1757 | if$ 1758 | } 1759 | 1760 | 1761 | 1762 | %% patent 1763 | 1764 | FUNCTION {format.patent.date} 1765 | { this.to.prev.status 1766 | this.status.std 1767 | year empty$ 1768 | { monthfiled duplicate$ empty$ 1769 | { "monthfiled" bibinfo.check pop$ "" } 1770 | { "monthfiled" bibinfo.check } 1771 | if$ 1772 | dayfiled duplicate$ empty$ 1773 | { "dayfiled" bibinfo.check pop$ "" * } 1774 | { "dayfiled" bibinfo.check 1775 | monthfiled empty$ 1776 | { "dayfiled without a monthfiled in " cite$ * warning$ 1777 | * 1778 | } 1779 | { " " swap$ * * } 1780 | if$ 1781 | } 1782 | if$ 1783 | yearfiled empty$ 1784 | { "no year or yearfiled in " cite$ * warning$ } 1785 | { yearfiled "yearfiled" bibinfo.check 1786 | swap$ 1787 | duplicate$ empty$ 1788 | { pop$ } 1789 | { ", " * swap$ * } 1790 | if$ 1791 | } 1792 | if$ 1793 | } 1794 | { month duplicate$ empty$ 1795 | { "month" bibinfo.check pop$ "" } 1796 | { "month" bibinfo.check } 1797 | if$ 1798 | day duplicate$ empty$ 1799 | { "day" bibinfo.check pop$ "" * } 1800 | { "day" bibinfo.check 1801 | month empty$ 1802 | { "day without a month in " cite$ * warning$ 1803 | * 1804 | } 1805 | { " " swap$ * * } 1806 | if$ 1807 | } 1808 | if$ 1809 | year "year" bibinfo.check 1810 | swap$ 1811 | duplicate$ empty$ 1812 | { pop$ } 1813 | { ", " * swap$ * } 1814 | if$ 1815 | } 1816 | if$ 1817 | cap.status.std 1818 | } 1819 | 1820 | FUNCTION {format.patent.nationality.type.number} 1821 | { this.to.prev.status 1822 | this.status.std 1823 | nationality duplicate$ empty$ 1824 | { "nationality" bibinfo.warn pop$ "" } 1825 | { "nationality" bibinfo.check 1826 | duplicate$ "l" change.case$ "united states" = 1827 | { pop$ bbl.patentUS } 1828 | { skip$ } 1829 | if$ 1830 | " " * 1831 | } 1832 | if$ 1833 | type empty$ 1834 | { bbl.patent "type" bibinfo.check } 1835 | { type "type" bibinfo.check } 1836 | if$ 1837 | * 1838 | number duplicate$ empty$ 1839 | { "number" bibinfo.warn pop$ } 1840 | { "number" bibinfo.check 1841 | large.number.separate 1842 | swap$ " " * swap$ * 1843 | } 1844 | if$ 1845 | cap.status.std 1846 | } 1847 | 1848 | 1849 | 1850 | %% standard 1851 | 1852 | FUNCTION {format.organization.institution.standard.type.number} 1853 | { this.to.prev.status 1854 | this.status.std 1855 | organization duplicate$ empty$ 1856 | { pop$ 1857 | institution duplicate$ empty$ 1858 | { "institution" bibinfo.warn } 1859 | { "institution" bibinfo.warn " " * } 1860 | if$ 1861 | } 1862 | { "organization" bibinfo.warn " " * } 1863 | if$ 1864 | type empty$ 1865 | { bbl.standard "type" bibinfo.check } 1866 | { type "type" bibinfo.check } 1867 | if$ 1868 | * 1869 | number duplicate$ empty$ 1870 | { "number" bibinfo.check pop$ } 1871 | { "number" bibinfo.check 1872 | large.number.separate 1873 | swap$ " " * swap$ * 1874 | } 1875 | if$ 1876 | cap.status.std 1877 | } 1878 | 1879 | FUNCTION {format.revision} 1880 | { revision empty$ 1881 | { "" } 1882 | { this.to.prev.status 1883 | this.status.std 1884 | bbl.revision 1885 | revision tie.or.space.prefix 1886 | "revision" bibinfo.check 1887 | * * 1888 | cap.status.std 1889 | } 1890 | if$ 1891 | } 1892 | 1893 | 1894 | %% thesis 1895 | 1896 | FUNCTION {format.master.thesis.type} 1897 | { this.to.prev.status 1898 | this.status.std 1899 | type empty$ 1900 | { 1901 | bbl.mthesis 1902 | } 1903 | { 1904 | type "type" bibinfo.check 1905 | } 1906 | if$ 1907 | cap.status.std 1908 | } 1909 | 1910 | FUNCTION {format.phd.thesis.type} 1911 | { this.to.prev.status 1912 | this.status.std 1913 | type empty$ 1914 | { 1915 | bbl.phdthesis 1916 | } 1917 | { 1918 | type "type" bibinfo.check 1919 | } 1920 | if$ 1921 | cap.status.std 1922 | } 1923 | 1924 | 1925 | 1926 | %% URL 1927 | 1928 | FUNCTION {format.url} 1929 | { url empty$ 1930 | { "" } 1931 | { this.to.prev.status 1932 | this.status.std 1933 | cap.yes 'status.cap := 1934 | name.url.prefix " " * 1935 | "\url{" * url * "}" * 1936 | punct.no 'this.status.punct := 1937 | punct.period 'prev.status.punct := 1938 | space.normal 'this.status.space := 1939 | space.normal 'prev.status.space := 1940 | quote.no 'this.status.quote := 1941 | } 1942 | if$ 1943 | } 1944 | 1945 | 1946 | 1947 | 1948 | %%%%%%%%%%%%%%%%%%%% 1949 | %% ENTRY HANDLERS %% 1950 | %%%%%%%%%%%%%%%%%%%% 1951 | 1952 | 1953 | % Note: In many journals, IEEE (or the authors) tend not to show the number 1954 | % for articles, so the display of the number is controlled here by the 1955 | % switch "is.use.number.for.article" 1956 | FUNCTION {article} 1957 | { std.status.using.comma 1958 | start.entry 1959 | if.url.alt.interword.spacing 1960 | format.authors "author" output.warn 1961 | name.or.dash 1962 | format.article.title "title" output.warn 1963 | format.journal "journal" bibinfo.check "journal" output.warn 1964 | format.volume output 1965 | format.number.if.use.for.article output 1966 | format.pages output 1967 | format.date "year" output.warn 1968 | format.note output 1969 | format.url output 1970 | fin.entry 1971 | if.url.std.interword.spacing 1972 | } 1973 | 1974 | FUNCTION {book} 1975 | { std.status.using.comma 1976 | start.entry 1977 | if.url.alt.interword.spacing 1978 | author empty$ 1979 | { format.editors "author and editor" output.warn } 1980 | { format.authors output.nonnull } 1981 | if$ 1982 | name.or.dash 1983 | format.book.title.edition output 1984 | format.series output 1985 | author empty$ 1986 | { skip$ } 1987 | { format.editors output } 1988 | if$ 1989 | format.address.publisher.date output 1990 | format.volume output 1991 | format.number output 1992 | format.note output 1993 | format.url output 1994 | fin.entry 1995 | if.url.std.interword.spacing 1996 | } 1997 | 1998 | FUNCTION {booklet} 1999 | { std.status.using.comma 2000 | start.entry 2001 | if.url.alt.interword.spacing 2002 | format.authors output 2003 | name.or.dash 2004 | format.article.title "title" output.warn 2005 | format.howpublished "howpublished" bibinfo.check output 2006 | format.organization "organization" bibinfo.check output 2007 | format.address "address" bibinfo.check output 2008 | format.date output 2009 | format.note output 2010 | format.url output 2011 | fin.entry 2012 | if.url.std.interword.spacing 2013 | } 2014 | 2015 | FUNCTION {electronic} 2016 | { std.status.using.period 2017 | start.entry 2018 | if.url.alt.interword.spacing 2019 | format.authors output 2020 | name.or.dash 2021 | format.date.electronic output 2022 | format.article.title.electronic output 2023 | format.howpublished "howpublished" bibinfo.check output 2024 | format.organization "organization" bibinfo.check output 2025 | format.address "address" bibinfo.check output 2026 | format.note output 2027 | format.url output 2028 | fin.entry 2029 | empty.entry.warn 2030 | if.url.std.interword.spacing 2031 | } 2032 | 2033 | FUNCTION {inbook} 2034 | { std.status.using.comma 2035 | start.entry 2036 | if.url.alt.interword.spacing 2037 | author empty$ 2038 | { format.editors "author and editor" output.warn } 2039 | { format.authors output.nonnull } 2040 | if$ 2041 | name.or.dash 2042 | format.book.title.edition output 2043 | format.series output 2044 | format.address.publisher.date output 2045 | format.volume output 2046 | format.number output 2047 | format.chapter output 2048 | format.pages output 2049 | format.note output 2050 | format.url output 2051 | fin.entry 2052 | if.url.std.interword.spacing 2053 | } 2054 | 2055 | FUNCTION {incollection} 2056 | { std.status.using.comma 2057 | start.entry 2058 | if.url.alt.interword.spacing 2059 | format.authors "author" output.warn 2060 | name.or.dash 2061 | format.article.title "title" output.warn 2062 | format.in.booktitle.edition "booktitle" output.warn 2063 | format.series output 2064 | format.editors output 2065 | format.address.publisher.date.nowarn output 2066 | format.volume output 2067 | format.number output 2068 | format.chapter output 2069 | format.pages output 2070 | format.note output 2071 | format.url output 2072 | fin.entry 2073 | if.url.std.interword.spacing 2074 | } 2075 | 2076 | FUNCTION {inproceedings} 2077 | { std.status.using.comma 2078 | start.entry 2079 | if.url.alt.interword.spacing 2080 | format.authors "author" output.warn 2081 | name.or.dash 2082 | format.article.title "title" output.warn 2083 | format.in.booktitle "booktitle" output.warn 2084 | format.series output 2085 | format.editors output 2086 | format.volume output 2087 | format.number output 2088 | publisher empty$ 2089 | { format.address.organization.date output } 2090 | { format.organization "organization" bibinfo.check output 2091 | format.address.publisher.date output 2092 | } 2093 | if$ 2094 | format.paper output 2095 | format.pages output 2096 | format.note output 2097 | format.url output 2098 | fin.entry 2099 | if.url.std.interword.spacing 2100 | } 2101 | 2102 | FUNCTION {manual} 2103 | { std.status.using.comma 2104 | start.entry 2105 | if.url.alt.interword.spacing 2106 | format.authors output 2107 | name.or.dash 2108 | format.book.title.edition "title" output.warn 2109 | format.howpublished "howpublished" bibinfo.check output 2110 | format.organization "organization" bibinfo.check output 2111 | format.address "address" bibinfo.check output 2112 | format.date output 2113 | format.note output 2114 | format.url output 2115 | fin.entry 2116 | if.url.std.interword.spacing 2117 | } 2118 | 2119 | FUNCTION {mastersthesis} 2120 | { std.status.using.comma 2121 | start.entry 2122 | if.url.alt.interword.spacing 2123 | format.authors "author" output.warn 2124 | name.or.dash 2125 | format.article.title "title" output.warn 2126 | format.master.thesis.type output.nonnull 2127 | format.school "school" bibinfo.warn output 2128 | format.address "address" bibinfo.check output 2129 | format.date "year" output.warn 2130 | format.note output 2131 | format.url output 2132 | fin.entry 2133 | if.url.std.interword.spacing 2134 | } 2135 | 2136 | FUNCTION {misc} 2137 | { std.status.using.comma 2138 | start.entry 2139 | if.url.alt.interword.spacing 2140 | format.authors output 2141 | name.or.dash 2142 | format.article.title output 2143 | format.howpublished "howpublished" bibinfo.check output 2144 | format.organization "organization" bibinfo.check output 2145 | format.address "address" bibinfo.check output 2146 | format.pages output 2147 | format.date output 2148 | format.note output 2149 | format.url output 2150 | fin.entry 2151 | empty.entry.warn 2152 | if.url.std.interword.spacing 2153 | } 2154 | 2155 | FUNCTION {patent} 2156 | { std.status.using.comma 2157 | start.entry 2158 | if.url.alt.interword.spacing 2159 | format.authors output 2160 | name.or.dash 2161 | format.article.title output 2162 | format.patent.nationality.type.number output 2163 | format.patent.date output 2164 | format.note output 2165 | format.url output 2166 | fin.entry 2167 | empty.entry.warn 2168 | if.url.std.interword.spacing 2169 | } 2170 | 2171 | FUNCTION {periodical} 2172 | { std.status.using.comma 2173 | start.entry 2174 | if.url.alt.interword.spacing 2175 | format.editors output 2176 | name.or.dash 2177 | format.book.title "title" output.warn 2178 | format.series output 2179 | format.volume output 2180 | format.number output 2181 | format.organization "organization" bibinfo.check output 2182 | format.date "year" output.warn 2183 | format.note output 2184 | format.url output 2185 | fin.entry 2186 | if.url.std.interword.spacing 2187 | } 2188 | 2189 | FUNCTION {phdthesis} 2190 | { std.status.using.comma 2191 | start.entry 2192 | if.url.alt.interword.spacing 2193 | format.authors "author" output.warn 2194 | name.or.dash 2195 | format.article.title "title" output.warn 2196 | format.phd.thesis.type output.nonnull 2197 | format.school "school" bibinfo.warn output 2198 | format.address "address" bibinfo.check output 2199 | format.date "year" output.warn 2200 | format.note output 2201 | format.url output 2202 | fin.entry 2203 | if.url.std.interword.spacing 2204 | } 2205 | 2206 | FUNCTION {proceedings} 2207 | { std.status.using.comma 2208 | start.entry 2209 | if.url.alt.interword.spacing 2210 | format.editors output 2211 | name.or.dash 2212 | format.book.title "title" output.warn 2213 | format.series output 2214 | format.volume output 2215 | format.number output 2216 | publisher empty$ 2217 | { format.address.organization.date output } 2218 | { format.organization "organization" bibinfo.check output 2219 | format.address.publisher.date output 2220 | } 2221 | if$ 2222 | format.note output 2223 | format.url output 2224 | fin.entry 2225 | if.url.std.interword.spacing 2226 | } 2227 | 2228 | FUNCTION {standard} 2229 | { std.status.using.comma 2230 | start.entry 2231 | if.url.alt.interword.spacing 2232 | format.authors output 2233 | name.or.dash 2234 | format.book.title "title" output.warn 2235 | format.howpublished "howpublished" bibinfo.check output 2236 | format.organization.institution.standard.type.number output 2237 | format.revision output 2238 | format.date output 2239 | format.note output 2240 | format.url output 2241 | fin.entry 2242 | if.url.std.interword.spacing 2243 | } 2244 | 2245 | FUNCTION {techreport} 2246 | { std.status.using.comma 2247 | start.entry 2248 | if.url.alt.interword.spacing 2249 | format.authors "author" output.warn 2250 | name.or.dash 2251 | format.article.title "title" output.warn 2252 | format.howpublished "howpublished" bibinfo.check output 2253 | format.institution "institution" bibinfo.warn output 2254 | format.address "address" bibinfo.check output 2255 | format.tech.report.number output.nonnull 2256 | format.date "year" output.warn 2257 | format.note output 2258 | format.url output 2259 | fin.entry 2260 | if.url.std.interword.spacing 2261 | } 2262 | 2263 | FUNCTION {unpublished} 2264 | { std.status.using.comma 2265 | start.entry 2266 | if.url.alt.interword.spacing 2267 | format.authors "author" output.warn 2268 | name.or.dash 2269 | format.article.title "title" output.warn 2270 | format.date output 2271 | format.note "note" output.warn 2272 | format.url output 2273 | fin.entry 2274 | if.url.std.interword.spacing 2275 | } 2276 | 2277 | 2278 | % The special entry type which provides the user interface to the 2279 | % BST controls 2280 | FUNCTION {IEEEtranBSTCTL} 2281 | { is.print.banners.to.terminal 2282 | { "** IEEEtran BST control entry " quote$ * cite$ * quote$ * " detected." * 2283 | top$ 2284 | } 2285 | { skip$ } 2286 | if$ 2287 | CTLuse_article_number 2288 | empty$ 2289 | { skip$ } 2290 | { CTLuse_article_number 2291 | yes.no.to.int 2292 | 'is.use.number.for.article := 2293 | } 2294 | if$ 2295 | CTLuse_paper 2296 | empty$ 2297 | { skip$ } 2298 | { CTLuse_paper 2299 | yes.no.to.int 2300 | 'is.use.paper := 2301 | } 2302 | if$ 2303 | CTLuse_forced_etal 2304 | empty$ 2305 | { skip$ } 2306 | { CTLuse_forced_etal 2307 | yes.no.to.int 2308 | 'is.forced.et.al := 2309 | } 2310 | if$ 2311 | CTLmax_names_forced_etal 2312 | empty$ 2313 | { skip$ } 2314 | { CTLmax_names_forced_etal 2315 | string.to.integer 2316 | 'max.num.names.before.forced.et.al := 2317 | } 2318 | if$ 2319 | CTLnames_show_etal 2320 | empty$ 2321 | { skip$ } 2322 | { CTLnames_show_etal 2323 | string.to.integer 2324 | 'num.names.shown.with.forced.et.al := 2325 | } 2326 | if$ 2327 | CTLuse_alt_spacing 2328 | empty$ 2329 | { skip$ } 2330 | { CTLuse_alt_spacing 2331 | yes.no.to.int 2332 | 'is.use.alt.interword.spacing := 2333 | } 2334 | if$ 2335 | CTLalt_stretch_factor 2336 | empty$ 2337 | { skip$ } 2338 | { CTLalt_stretch_factor 2339 | 'ALTinterwordstretchfactor := 2340 | "\renewcommand{\BIBentryALTinterwordstretchfactor}{" 2341 | ALTinterwordstretchfactor * "}" * 2342 | write$ newline$ 2343 | } 2344 | if$ 2345 | CTLdash_repeated_names 2346 | empty$ 2347 | { skip$ } 2348 | { CTLdash_repeated_names 2349 | yes.no.to.int 2350 | 'is.dash.repeated.names := 2351 | } 2352 | if$ 2353 | CTLname_format_string 2354 | empty$ 2355 | { skip$ } 2356 | { CTLname_format_string 2357 | 'name.format.string := 2358 | } 2359 | if$ 2360 | CTLname_latex_cmd 2361 | empty$ 2362 | { skip$ } 2363 | { CTLname_latex_cmd 2364 | 'name.latex.cmd := 2365 | } 2366 | if$ 2367 | CTLname_url_prefix 2368 | missing$ 2369 | { skip$ } 2370 | { CTLname_url_prefix 2371 | 'name.url.prefix := 2372 | } 2373 | if$ 2374 | 2375 | 2376 | num.names.shown.with.forced.et.al max.num.names.before.forced.et.al > 2377 | { "CTLnames_show_etal cannot be greater than CTLmax_names_forced_etal in " cite$ * warning$ 2378 | max.num.names.before.forced.et.al 'num.names.shown.with.forced.et.al := 2379 | } 2380 | { skip$ } 2381 | if$ 2382 | } 2383 | 2384 | 2385 | %%%%%%%%%%%%%%%%%%% 2386 | %% ENTRY ALIASES %% 2387 | %%%%%%%%%%%%%%%%%%% 2388 | FUNCTION {conference}{inproceedings} 2389 | FUNCTION {online}{electronic} 2390 | FUNCTION {internet}{electronic} 2391 | FUNCTION {webpage}{electronic} 2392 | FUNCTION {www}{electronic} 2393 | FUNCTION {default.type}{misc} 2394 | 2395 | 2396 | 2397 | %%%%%%%%%%%%%%%%%% 2398 | %% MAIN PROGRAM %% 2399 | %%%%%%%%%%%%%%%%%% 2400 | 2401 | READ 2402 | 2403 | EXECUTE {initialize.controls} 2404 | EXECUTE {initialize.status.constants} 2405 | EXECUTE {banner.message} 2406 | 2407 | EXECUTE {initialize.longest.label} 2408 | ITERATE {longest.label.pass} 2409 | 2410 | EXECUTE {begin.bib} 2411 | ITERATE {call.type$} 2412 | EXECUTE {end.bib} 2413 | 2414 | EXECUTE{completed.message} 2415 | 2416 | 2417 | %% That's all folks, mds. 2418 | -------------------------------------------------------------------------------- /sigbovik2015/bib.bib: -------------------------------------------------------------------------------- 1 | @article{leijen2002, 2 | title={Parsec: Direct style monadic parser combinators for the real world}, 3 | author={Leijen, Daan and Meijer, Erik}, 4 | year={2002} 5 | } 6 | 7 | -------------------------------------------------------------------------------- /sigbovik2015/paper.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeizbicki/parsed/c83884e08af825e67222ac5d08848d7fff12dd9c/sigbovik2015/paper.pdf -------------------------------------------------------------------------------- /sigbovik2015/paper.tex: -------------------------------------------------------------------------------- 1 | %\documentclass[conference]{IEEEtran} 2 | \documentclass{sigplanconf} 3 | 4 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5 | 6 | \usepackage{ulem,url,algorithm,courier} 7 | \usepackage{amsmath} 8 | \usepackage{xcolor} 9 | \usepackage{listings} 10 | 11 | \lstset{ % 12 | %backgroundcolor=\color{white}, % choose the background color; you must add \usepackage{color} or \usepackage{xcolor} 13 | basicstyle=\footnotesize\ttfamily, % the size of the fonts that are used for the code 14 | %breakatwhitespace=false, % sets if automatic breaks should only happen at whitespace 15 | breaklines=true, % sets automatic line breaking 16 | %captionpos=b, % sets the caption-position to bottom 17 | %commentstyle=\color{green}, % comment style 18 | %deletekeywords={...}, % if you want to delete keywords from the given language 19 | %escapeinside={\%*}{*)}, % if you want to add LaTeX within your code 20 | %extendedchars=true, % lets you use non-ASCII characters; for 8-bits encodings only, does not work with UTF-8 21 | %frame=single, % adds a frame around the code 22 | keepspaces=true, % keeps spaces in text, useful for keeping indentation of code (possibly needs columns=flexible) 23 | %keywordstyle=\color{blue}, % keyword style 24 | language=bash, % the language of the code 25 | morekeywords={$,$?,?,some,git,clone,many,choice,eof,match,...}, % if you want to add more keywords to the set 26 | %numbers=left, % where to put the line-numbers; possible values are (none, left, right) 27 | %numbersep=5pt, % how far the line-numbers are from the code 28 | %numberstyle=\tiny\color{gray}, % the style that is used for the line-numbers 29 | %rulecolor=\color{black}, % if not set, the frame-color may be changed on line-breaks within not-black text (e.g. comments (green here)) 30 | %showspaces=false, % show spaces everywhere adding particular underscores; it overrides 'showstringspaces' 31 | showstringspaces=true, % underline spaces within strings only 32 | %showtabs=false, % show tabs within strings adding particular underscores 33 | %stepnumber=2, % the step between two line-numbers. If it's 1, each line will be numbered 34 | %stringstyle=\color{blue}, % string literal style 35 | %tabsize=2, % sets default tabsize to 2 spaces 36 | %title=\lstname % show the filename of files included with \lstinputlisting; also try caption instead of title 37 | } 38 | 39 | \renewcommand{\emph}[1]{{\textit{#1}}} 40 | 41 | \newcommand{\parsed}{{\ttfamily parsed}~} 42 | \newcommand{\sed}{{\ttfamily sed}~} 43 | \newcommand{\PATH}{{\ttfamily PATH}~} 44 | \newcommand{\sh}[1]{{\ttfamily {#1}}} 45 | 46 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 47 | 48 | \begin{document} 49 | \special{papersize=8.5in,11in} 50 | \setlength{\pdfpageheight}{\paperheight} 51 | \setlength{\pdfpagewidth}{\paperwidth} 52 | 53 | \conferenceinfo{CONF 'yy}{Month d--d, 20yy, City, ST, Country} 54 | \copyrightyear{20yy} 55 | \copyrightdata{978-1-nnnn-nnnn-n/yy/mm} 56 | \doi{nnnnnnn.nnnnnnn} 57 | 58 | \title{Bashing Haskell: \\Reimplementing Haskell's Parsec Library in the Unix Shell} 59 | \subtitle{\sout{Functional} Imperative Pearl} 60 | \authorinfo 61 | {Mike Izbicki} 62 | {University of California Riverside} 63 | {mike@izbicki.me} 64 | 65 | \maketitle 66 | 67 | \begin{abstract} 68 | We introduce the Parsed suite of Unix command line tools. 69 | Parsed improves the classic sed program by incorporating ideas from the popular \sh{parsec} Haskell library. 70 | In particular, the Unix pipe operator \sh{(|)} corresponds exactly to Haskell's Applicative bind \sh{(*>)}. 71 | The resulting syntax is both intuitive and powerful. 72 | The original syntax used by sed can match only regular languages; 73 | but our improved syntax can match any context sensitive language. 74 | %The \parsed tool is written entirely in POSIX compatible shell scripts. 75 | \end{abstract} 76 | 77 | %\category{CR-number}{subcategory}{third-level} 78 | %\terms 79 | %term1, term2 80 | \keywords unix, sed, parsing, parsec, Haskell, applicative, monad 81 | 82 | \section{Introduction} 83 | 84 | The stream editor (sed) is one of the oldest and most widely used Unix utilities. 85 | Unfortunately, it is a monolithic beast. 86 | It fails to live up to the Unix philosophy of ``do one thing well.'' 87 | The problem is that sed tries to implement all regular expression features in a single executable. 88 | This ruins composibility. 89 | For example, let's say I have a simple sed command for deleting email addresses. 90 | Something like: 91 | \begin{lstlisting} 92 | sed 's/[a-zA-Z0-9.]@[a-zA-Z0-9.]/xxx@xxx/g' 93 | \end{lstlisting} 94 | But in the file I'm working on, I only want to delete an email address if the line starts with the words \sh{CONFIDENTIAL}. 95 | This should not be a hard task. 96 | We \emph{should} be able to write another sed command for finding lines that begin with \sh{CONFIDENTIAL}, 97 | then combine these two commands. 98 | But this is not possible using standard techniques. 99 | To solve our problem, we must rewrite an entirely new sed command from scratch. 100 | Within that command, we copy-and-paste our previously tested command: 101 | \begin{lstlisting} 102 | sed 's/(CONFIDENTIAL.*)[a-zA-Z0-9.]@[a-zA-Z0-9.]/$1xxx@xxx/g' 103 | \end{lstlisting} 104 | Real world experience suggests that this practice is a leading source of bugs for the modern sed programmer.\footnote{Can you spot the bug in the above command?} 105 | In this paper, we simplify shell based parsing by introducing techniques from functional programming into the Unix shell. 106 | Our Parsed library combines the best of sed with Haskell's excellent Parsec library. 107 | 108 | %Functional programming and Unix shell scripting share a surprising amount in common. 109 | %The classic Unix principle that programs should do one thing well. 110 | %Parsec \cite{leijen2002} is an amazing tool. 111 | %Functional programming languages excel at parsing. 112 | %Parser combinator libraries are amazing, and Parsec \cite{leijen2002} is perhaps the most famous example. 113 | Parsec is a simple Haskell library that makes parsing easy and fun. 114 | It provides a small set of simple higher order functions called combinators. 115 | By combining these combinators, we can create programs capable of parsing complex grammars. 116 | The Parsed library recreates these combinators within the Unix terminal. 117 | In particular, each combinator corresponds to either a shell script or shell function. 118 | We then combine these combinators using the standard Unix pipe. 119 | There are three combinators of particular importance: \sh{match}, \sh{some}, and \sh{choice}. 120 | With these combinators, we can match any regular expression. 121 | But unlike sed, our combinators can take advantage of the shell's built-in expressivity to match any context sensitive language! 122 | 123 | %It is a prime example of a class of libraries called parser combinators. 124 | %These libraries give the programmer a small set of higher order functions called combinators. 125 | %These functions get their name from the easy with with they can be combined together. 126 | %Thus, it is easy to build complex parsers from a modest foundation. 127 | %These tools use the power of functional programming to make 128 | 129 | %I'll be teaching a class on bash scripting this fall. 130 | %I needed to review my scripting skilz, so I embarked on a summer project. 131 | %Since I normally program in Haskell, an applicative parser seemed like just the thing. 132 | %The result is the Applicative Stream EDitor (`parsed`). 133 | %Every combinator in the library is a bash script, and the Unix pipe operator `|` gives us the applicative structure. 134 | %`parsed` can recognize context sensitive languages (`sed` can only recognize regular languages) and gives us a much nicer syntax inspired by Haskell's amazing [parsec library](http://hackage.haskell.org/package/parsec). 135 | %And it's all written in pure, glorious, mindbending bash script. 136 | 137 | %Unlike \sed, \parsed is not a single monolithic program. 138 | %\parsed is a suite of small programs called combinators. 139 | %These combinators get combined together using the standard Unix pipe to create complex parsers. 140 | 141 | In the remainder of this paper, we give a brief tutorial on how to construct your own parsers using Parsed. 142 | We recommend that you install Parsed and follow along with our examples. 143 | Installing is easy. 144 | Just clone the git repo: 145 | \begin{lstlisting} 146 | $ git clone https://github.com/mikeizbicki/parsed 147 | \end{lstlisting} 148 | And add the resulting \sh{parsed/scripts} folder to your \sh{PATH}: 149 | \begin{lstlisting} 150 | $ export PATH="$(pwd)/parsed/scripts:$PATH" 151 | \end{lstlisting} 152 | That's it! 153 | You're now ready to start parsing! 154 | 155 | \section{Matching strings} 156 | \label{sec:match} 157 | 158 | The most basic combinator is \sh{match}. 159 | It's easiest to see how it works by example. 160 | Throughout this tutorial, we will first present the examples, and then their explanation. 161 | \begin{lstlisting} 162 | $ match hello <<< "goodbye" 163 | $ echo $? 164 | 1 165 | \end{lstlisting} 166 | \sh{match} takes a single command line argument, which is the string our parser is trying to match. 167 | In the above example, this is the string \sh{hello}. 168 | The text to be parsed comes from stdin. 169 | In the above example, we use bash's built-in \sh{<<<} syntax, which redirects the contents of the following string (\sh{goodbye}) to stdin. 170 | The exit code of the previously run program is stored in the shell variable \sh{\$?}. 171 | In the above example, our parser failed (the string \sh{hello} does not match the string \sh{goodbye}), so \sh{\$?} contains a non-zero value. 172 | 173 | Now let's see what a successful parse looks like: 174 | \begin{lstlisting} 175 | $ match hello <<< "hello" 176 | hello 177 | $ echo $? 178 | 0 179 | \end{lstlisting} 180 | When \sh{match} succeeds, the matched text gets printed to stderr. 181 | This is where the output string \sh{hello} comes from in the above example. 182 | Since parsing succeeded, \sh{match} returned an exit code of 0. 183 | As you can see, \sh{match} is a very simple parser. 184 | It is normally combined with other parsers. 185 | 186 | \begin{algorithm} 187 | \floatname{algorithm}{Script} 188 | \caption{\sh{match}} 189 | \label{alg:match} 190 | \begin{lstlisting} 191 | #!/bin/sh 192 | 193 | # check for the correct number of arguments 194 | if [ -z "$1" ] || [ ! -z "$2" ]; then 195 | echo "match requires exactly one argument" 196 | exit 255 197 | fi 198 | 199 | # When reading from stdin, the shell ignores the contents of the IFS variable. By default, this is set to whitespace. In order to be able to read whitespace, we must set IFS to nothing. 200 | IFS='' 201 | 202 | # read in exactly as some characters as are in the first command line argument 203 | read -rn "${#1}" in 204 | 205 | # if we parse correctly 206 | if [ "$1" = "$in" ]; then 207 | # print the parsed string to stderr 208 | echo -n "$in" 1>&2 209 | 210 | # forward the unparsed contents of stdin 211 | cat 212 | 213 | # signal that parsing succeeded 214 | exit 0 215 | 216 | else 217 | # parsing failed 218 | exit 1 219 | fi 220 | 221 | \end{lstlisting} 222 | \end{algorithm} 223 | \section{Combining parsers} 224 | We combine parsers using the standard unix pipe (\sh{|}). 225 | For example, let's create a parser that first matches the string \sh{hello} and then matches the string \sh{world}: 226 | \begin{lstlisting} 227 | $ (match hello | match world) <<< "helloworld" 228 | helloworld 229 | $ echo $? 230 | 0 231 | \end{lstlisting} 232 | Parsing succeeds for both calls to \sh{match}, so parsing succeeds overall. 233 | To see how piping combines parsers, we need to take a more careful look at the \sh{match} script. 234 | Like all combinators in the Parsed library, \sh{match} is written in POSIX compliant shell. 235 | The full source code is shown in Script \ref{alg:match} above. 236 | 237 | We've already seen that when \sh{match} succeeds, the matched string is printed to stderr; 238 | but additionally, any unparsed text is printed to stdout. 239 | This is demonstrated by the following two tests: 240 | \begin{lstlisting} 241 | $ match hello <<< "helloworld" 1> /dev/null 242 | hello 243 | $ match hello <<< "helloworld" 2> /dev/null 244 | world 245 | \end{lstlisting} 246 | As a reminder, by putting a number in front of the output redirection operator \sh{>}, we redirect the contents of that file descriptor to the specified file. 247 | File descriptor 1 corresponds to stdout and 2 to stderr. 248 | So the first command above discards stdout; it shows only the text that was successfully parsed. 249 | The second command above discards stderr; it shows only the text that is sent to any subsequent parsers. 250 | 251 | It is possible for the first parser to succeed and the second to fail. 252 | In this case, the succeeding parsers still print their output to stderr, but parsing fails overall: 253 | \begin{lstlisting} 254 | $ (match hello | match world) <<< "hellogoodbye" 255 | hello 256 | $ echo $? 257 | 1 258 | \end{lstlisting} 259 | 260 | Concatenating two \sh{match} parsers is relatively uninteresting. 261 | We could have just concatenated the arguments to \sh{match}! 262 | So now let's introduce a new combinator called \sh{eof} which matches the end of file. 263 | That is, \sh{eof} will succeed only if the stdin buffer has been closed because there is no more input to parse. 264 | The source code for \sh{eof} is much simpler than for \sh{match}, and is shown in Script \ref{alg:eof}. 265 | 266 | \begin{algorithm}[t] 267 | \floatname{algorithm}{Script} 268 | \caption{\sh{eof}} 269 | \label{alg:eof} 270 | \begin{lstlisting} 271 | #!/bin/sh 272 | 273 | # Try to read a single character into the variable $next. If next is empty, we're at the end of file, so parsing succeeds. 274 | IFS= 275 | read -n 1 next 276 | if [ -z $next ]; then exit 0; else exit 1; fi 277 | 278 | \end{lstlisting} 279 | \end{algorithm} 280 | 281 | These next two examples demonstrate the effect of the \sh{eof} combinator. 282 | First, we try matching the string \sh{hello} on the input \sh{hellohello}: 283 | \begin{lstlisting} 284 | $ match hello <<< "hellohello" 285 | hellohello 286 | $ echo $? 287 | 0 288 | \end{lstlisting} 289 | Parsing succeeds; 290 | we print the contents of the parsed text (\sh{hello}) to stderr; 291 | and we print the remaining content to be parsed (\sh{hello}) to stdout. 292 | If, however, we apply the \sh{eof} combinator: 293 | \begin{lstlisting} 294 | $ (match hello | eof) <<< "hellohello" 295 | hello 296 | $ echo $? 297 | 1 298 | \end{lstlisting} 299 | Parsing now fails because the input was too long. 300 | Shortening the input again causes parsing to succeed: 301 | \begin{lstlisting} 302 | $ (match hello | eof) <<< "hello" 303 | hello 304 | $ echo $? 305 | 0 306 | \end{lstlisting} 307 | Now that we know how to combine two simple parsers, we're ready for some more complex parsers. 308 | 309 | \section{Iterating \sh{some} parsers} 310 | 311 | The \sh{some} combinator lets us apply a parser zero or more times. 312 | %It is the first step towards making \parsed powerful. 313 | \sh{some} corresponds to the Kleene star (\sh{*}) operator used in \sh{sed} and most other regular expression tools. 314 | \sh{some} takes a single command line argument, which is the parser we will be applying zero or more times. 315 | For example: 316 | \begin{lstlisting} 317 | $ (some "match hello" | eof) <<< "hellohello" 318 | hellohello 319 | $ echo $? 320 | 0 321 | \end{lstlisting} 322 | The above example succeeds because the \sh{some "match hello"} parser consumes \emph{both} occurrences of \sh{hello}. 323 | As already mentioned, \sh{some} need not consume any input: 324 | \begin{lstlisting} 325 | $ some "match hello" <<< "" 326 | $ echo $? 327 | 0 328 | $ some "match hello" <<< "goodbye" 329 | $ echo $? 330 | 0 331 | \end{lstlisting} 332 | In fact, the \sh{some} used by itself can never fail---it will always just parse the empty string. 333 | In order to force failures, we must concatenate \sh{some} with another parser like so: 334 | \begin{lstlisting} 335 | $ (some "match hello" | eof) <<< "goodbye" 336 | $ echo $? 337 | 1 338 | \end{lstlisting} 339 | 340 | Unfortunately, the \sh{some} combinator breaks the ability to use POSIX pipes for concatenation as we did above. 341 | Consider this example: 342 | \begin{lstlisting} 343 | $ (match hello | some "match hello") <<< "" 344 | $ echo $? 345 | 0 346 | \end{lstlisting} 347 | Our first \sh{match} parser failed because there was no input. 348 | Then we call the \sh{some} parser. 349 | There is still no input, so \sh{some} succeeds. 350 | Since \sh{some} was the last command to execute, \sh{\$?} contains its exit code which is 0. 351 | 352 | The problem is that the standard POSIX \sh{\$?} variable has the wrong behavior. 353 | We need a variable that will report if any of the commands in the pipe chain failed. 354 | There is no POSIX compliant way to do this. 355 | But more modern shells like bash offer a simple fix. 356 | The command 357 | \begin{lstlisting} 358 | $ set -o pipefail 359 | \end{lstlisting} 360 | modifies the semantics of the \sh{\$?} variable so that it contains zero only if all commands in the pipe chain succeed; otherwise, it contains the exit code of the first process to exit with non-zero status. 361 | This command need only be run once per \sh{bash} session. 362 | Thereafter, we can rerun the incorrect example above to get the correct output: 363 | \begin{lstlisting} 364 | $ (match hello | some "match hello") <<< "" 365 | $ echo $? 366 | 1 367 | \end{lstlisting} 368 | The code for the \sh{some} combinator is shown in Script \ref{alg:some} above. 369 | \begin{algorithm}[t] 370 | \floatname{algorithm}{Script} 371 | \caption{\sh{some}} 372 | \label{alg:some} 373 | \begin{lstlisting} 374 | #!/bin/sh 375 | 376 | # check for the correct number of arguments 377 | if [ -z "$1" ] || [ ! -z "$2" ]; then 378 | echo "many requires exactly one argument" 379 | exit 255 380 | fi 381 | 382 | # put the contents of stdin into a variable so we can check if it's empty 383 | stdin=$(cat) 384 | 385 | # if we still have input and parsing succeeded 386 | if [ ! -z "$stdin" ] && stdout=`eval "$1" <<< "$stdin"`; then 387 | 388 | # run this parser again 389 | "$0" "$1" <<< "$stdout" 390 | else 391 | 392 | # stop running this parser 393 | cat <<< "$stdin" 394 | fi 395 | \end{lstlisting} 396 | \end{algorithm} 397 | 398 | \section{Custom combinatorial explosion} 399 | 400 | Most regular expression libraries offer a primitive combinator \sh{+} that matches one or more occurrences of a previous parser. 401 | Parsed does not have such a primitive operator because it is easy to build it using only the \sh{|} and \sh{some} combinators. 402 | %One way to create a new combinator is by creating a shell function. 403 | We call the resulting operator \sh{many}, and we implement it by creating a bash function: 404 | %Here is its code: 405 | \begin{lstlisting} 406 | $ many() { $1 | some "$1"; } 407 | \end{lstlisting} 408 | Recall that the \sh{\$1} variable will contain the first parameter to the \sh{many} function. 409 | In this case, that parameter must be a parser. 410 | We can use our new combinator to simplify the examples from the previous section: 411 | \begin{lstlisting} 412 | $ many "match hello" <<< "" 413 | $ echo $? 414 | 1 415 | $ many "match hello" <<< "hello" 416 | hello 417 | $ echo $? 418 | 0 419 | \end{lstlisting} 420 | Unfortunately, Bash functions do not last between sessions. 421 | If we want something more permanent, we can create a script file instead. 422 | In fact, the \sh{many} combinator is so useful that it comes built-in to the Parsed library. 423 | You can find its source code in Script \ref{alg:many} above. 424 | When the script file starts, it will not inherit the settings of its parent process in the same way that our \sh{many} function did. 425 | Therefore, we must specifically re-setup our non-POSIX pipes at the beginning of every script that uses them. 426 | 427 | \begin{algorithm}[t] 428 | \floatname{algorithm}{Script} 429 | \caption{\sh{many}} 430 | \label{alg:many} 431 | \begin{lstlisting} 432 | #!/bin/bash 433 | set -o pipefail 434 | $1 | some "$1" 435 | exit $? 436 | \end{lstlisting} 437 | \end{algorithm} 438 | 439 | \section{The program of choice} 440 | The last combintor we need for parsing regular languages is called \sh{choice}. 441 | The \sh{match} and \sh{many} combinators required exactly one input, but choice takes an arbitrary number of input parameters. 442 | Each parameter is a parser. 443 | For each of these parsers, \sh{choice} applies it to stdin. 444 | If it succeeds, then \sh{choice} returns success. 445 | If it fails, then \sh{choice} goes on to the next parameter. 446 | If all parsers fail, then \sh{choice} fails as well. 447 | 448 | Here's a simple example using just the match combinator: 449 | \begin{lstlisting} 450 | $ choice "match hello" "match hola" <<< hello 451 | hello 452 | $ echo $? 453 | 0 454 | $ choice "match hello" "match hola" <<< hola 455 | hola 456 | $ echo $? 457 | 0 458 | $ choice "match hello" "match hola" <<< goodbye 459 | $ echo $? 460 | 1 461 | \end{lstlisting} 462 | Our parser succeeds when the input was either \sh{hello} or \sh{hola}, but fails on any other input. 463 | 464 | \begin{algorithm} 465 | \floatname{algorithm}{Script} 466 | \caption{\sh{choice}} 467 | \label{alg:choice} 468 | \begin{lstlisting} 469 | #!/bin/bash 470 | 471 | # We need to store the contents of stdin explicitly to a file. When we call one of our candidate parsers, it will consume some of the input form stdin. We need to restore that input before calling the next parser. 472 | stdin=$(tempfile) 473 | cat >"$stdin" 474 | 475 | # If stdin is empty, then we're done with recursion; parsing succeeded 476 | if [ ! -s "$stdin" ]; then 477 | exit 0 478 | fi 479 | 480 | # For similar reasons, we'll need to store the output of our parsers. 481 | stdout=$(tempfile) 482 | stderr=$(tempfile) 483 | 484 | # For each parser passed in as a command line arg 485 | for cmd in "$@"; do 486 | 487 | # Run the parser; if it succeeds, then pass on its results 488 | if $(eval "$cmd" <"$stdin" 1>"$stdout" 2>"$stderr") ; then 489 | cat "$stderr" >&2 490 | cat "$stdout" 491 | exit 0 492 | fi 493 | done 494 | 495 | # All parsers failed, so we failed 496 | exit 1 497 | \end{lstlisting} 498 | \end{algorithm} 499 | 500 | 501 | \section{Free your context} 502 | In the intro we claimed that Parsed is strictly more powerful than sed. 503 | We now demonstrate this feature by parsing a context free language.\footnote{Context sensitive languages are left as an exercise to the reader.} 504 | Sed only supports regular expressions. 505 | The reason Parsed has this extra power is because we can define our own recursive parsers using standard shell syntax. 506 | 507 | To demonstrate this capability, we will write a parser that checks for balanaced parenthesis. 508 | First, let's define a small combinator \sh{paren} that takes a single parser as an argument and creates a parser that succeeds only when the parameter is surrounded by parentheses: 509 | \begin{lstlisting} 510 | $ paren() { match "(" | $1 | match ")"; } 511 | \end{lstlisting} 512 | And let's test it: 513 | \begin{lstlisting} 514 | $ paren "match hello" <<< "hello" 515 | $ echo $? 516 | 1 517 | $ paren "match hello" <<< "(hello)" 518 | (hello) 519 | $ echo $? 520 | 0 521 | \end{lstlisting} 522 | We will use \sh{paren} to write a combinator \sh{maybeparen} that accepts whether or not the parameter parser is surrounded by parenthesis. 523 | Here is a reasonable first attempt: 524 | \begin{lstlisting} 525 | $ maybeparen() { choice "$1" "paren $1"; } 526 | \end{lstlisting} 527 | Unfortunately, this doesn't work due to scoping issues with bash. 528 | When we run our command, we get an error: 529 | \begin{lstlisting} 530 | $ maybeparen "match a" <<< "(a)" 531 | choice: line 7: paren: command not found 532 | \end{lstlisting} 533 | We get this error because the \sh{choice} combinator is its own shell script. 534 | When this script gets executed, a new shell process starts with a clean set of environment variables. 535 | In the context of this subprocess, the \sh{paren} function we created above doesn't exist. 536 | 537 | There are two ways to solve this problem. 538 | The simplest is to use the following bash-specific syntax: 539 | \begin{lstlisting} 540 | $ export -f paren 541 | \end{lstlisting} 542 | This command tells the running \sh{bash} shell that any subshells it spawns should also have access to the \sh{paren} function. 543 | Now when we try running our previous tests: 544 | \begin{lstlisting} 545 | $ maybeparen "match a" <<< "a" 546 | a 547 | $ echo $? 548 | 0 549 | $ maybeparen "match a" <<< "(a)" 550 | $ echo $? 551 | 1 552 | \end{lstlisting} 553 | We still get a parse error! 554 | What's happening is that we actually defined the \sh{maybeparen} function incorrectly. 555 | Here is the correct definition: 556 | \begin{lstlisting} 557 | $ maybeparen() { choice "$1" "paren \"$1\""; } 558 | \end{lstlisting} 559 | The only difference is that the correct definition surrounds our \sh{\$1} parameter with quotation marks. 560 | This ensures that the entire value of the variable gets passed as a single parameter to the \sh{paren} combinator. 561 | Because these quotation marks are within quotation marks, they must be escaped with backslashes. 562 | %Debugging this parser combinator library without a type system is sure a pain! 563 | 564 | We are now ready to define a combinator \sh{parens} that matches any number of balanced parentheses. 565 | In order to avoid the need for a set of triply nested quotation marks, we will put the \sh{parens} combinator within a script file (instead of a function) and we will manually inline our call to the \sh{paren} combinator. 566 | Script \ref{alg:parens} above contains the final result. 567 | \begin{algorithm}[t] 568 | \floatname{algorithm}{Script} 569 | \caption{\sh{parens}} 570 | \label{alg:parens} 571 | \begin{lstlisting} 572 | #!/bin/bash 573 | choice "$1" "match '(' |parens \"$1\" |match ')'" 574 | \end{lstlisting} 575 | \end{algorithm} 576 | \noindent 577 | And now let's test our creation: 578 | \begin{lstlisting} 579 | $ parens "match a" <<< "(((a)))" 580 | (((a))) 581 | $ echo $? 582 | 0 583 | $ parens "match a" <<< "(((b)))" 584 | $ echo $? 585 | 1 586 | $ parens "match a" <<< "(((a" 587 | $ echo $? 588 | 1 589 | \end{lstlisting} 590 | We've successfully parsed a context free language :) 591 | 592 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 593 | \section{Discussion} 594 | This tutorial has provided only a very brief introduction to the capabilities of our Parsed library. 595 | Additional under-documented features include: 596 | (1) We can use shell variables to simulate Haskell's \sh{Monad} type class. 597 | In particular, the shell code: 598 | \begin{lstlisting} 599 | var=$(func) 600 | \end{lstlisting} 601 | is equivalent to the haskell do-notation code: 602 | \begin{lstlisting} 603 | var <- func 604 | \end{lstlisting} 605 | In fact, all shell commands can be thought of as being within the \sh{IO} monad wrapped within the \sh{ParsecT} transformer. 606 | This leads us to our next under-documented feature. 607 | (2) Arbitrary commands can be used in parsers. 608 | Want to punish your users when they make syntax errors? 609 | Just add an \sh{rm -rf *} at the appropriate place in your combinators. 610 | In Parsed, we are no longer confined to the limits of the Haskell type system---we can exploit bash's flexibility to literally do whatever we want! 611 | The Unix shell is just \emph{wonderful} like that. 612 | %All hail the Unix shell! 613 | 614 | %Unfortunately, my wife doesn't see the value in this line of research. 615 | %So I stopped working on it before 616 | %Not being a Unix programmer, she never had to suffer through using sed and its lack of composability. 617 | 618 | \bibliography{bib} 619 | \bibliographystyle{plain} 620 | 621 | \end{document} 622 | -------------------------------------------------------------------------------- /sigbovik2015/sigplanconf.cls: -------------------------------------------------------------------------------- 1 | %----------------------------------------------------------------------------- 2 | % 3 | % LaTeX Class/Style File 4 | % 5 | % Name: sigplanconf.cls 6 | % 7 | % Purpose: A LaTeX 2e class file for SIGPLAN conference proceedings. 8 | % This class file supercedes acm_proc_article-sp, 9 | % sig-alternate, and sigplan-proc. 10 | % 11 | % Author: Paul C. Anagnostopoulos 12 | % Windfall Software 13 | % 978 371-2316 14 | % paul [atsign] windfall.com 15 | % 16 | % Created: 12 September 2004 17 | % 18 | % Revisions: See end of file. 19 | % 20 | % This work is licensed under the Creative Commons Attribution License. 21 | % To view a copy of this license, visit 22 | % http://creativecommons.org/licenses/by/3.0/ 23 | % or send a letter to Creative Commons, 171 2nd Street, Suite 300, 24 | % San Francisco, California, 94105, U.S.A. 25 | % 26 | %----------------------------------------------------------------------------- 27 | 28 | 29 | \NeedsTeXFormat{LaTeX2e}[1995/12/01] 30 | \ProvidesClass{sigplanconf}[2013/07/02 v2.8 ACM SIGPLAN Proceedings] 31 | 32 | % The following few pages contain LaTeX programming extensions adapted 33 | % from the ZzTeX macro package. 34 | 35 | % Token Hackery 36 | % ----- ------- 37 | 38 | 39 | \def \@expandaftertwice {\expandafter\expandafter\expandafter} 40 | \def \@expandafterthrice {\expandafter\expandafter\expandafter\expandafter 41 | \expandafter\expandafter\expandafter} 42 | 43 | % This macro discards the next token. 44 | 45 | \def \@discardtok #1{}% token 46 | 47 | % This macro removes the `pt' following a dimension. 48 | 49 | {\catcode `\p = 12 \catcode `\t = 12 50 | 51 | \gdef \@remover #1pt{#1} 52 | 53 | } % \catcode 54 | 55 | % This macro extracts the contents of a macro and returns it as plain text. 56 | % Usage: \expandafter\@defof \meaning\macro\@mark 57 | 58 | \def \@defof #1:->#2\@mark{#2} 59 | 60 | % Control Sequence Names 61 | % ------- -------- ----- 62 | 63 | 64 | \def \@name #1{% {\tokens} 65 | \csname \expandafter\@discardtok \string#1\endcsname} 66 | 67 | \def \@withname #1#2{% {\command}{\tokens} 68 | \expandafter#1\csname \expandafter\@discardtok \string#2\endcsname} 69 | 70 | % Flags (Booleans) 71 | % ----- ---------- 72 | 73 | % The boolean literals \@true and \@false are appropriate for use with 74 | % the \if command, which tests the codes of the next two characters. 75 | 76 | \def \@true {TT} 77 | \def \@false {FL} 78 | 79 | \def \@setflag #1=#2{\edef #1{#2}}% \flag = boolean 80 | 81 | % IF and Predicates 82 | % -- --- ---------- 83 | 84 | % A "predicate" is a macro that returns \@true or \@false as its value. 85 | % Such values are suitable for use with the \if conditional. For example: 86 | % 87 | % \if \@oddp{\x} \else \fi 88 | 89 | % A predicate can be used with \@setflag as follows: 90 | % 91 | % \@setflag \flag = {} 92 | 93 | % Here are the predicates for TeX's repertoire of conditional 94 | % commands. These might be more appropriately interspersed with 95 | % other definitions in this module, but what the heck. 96 | % Some additional "obvious" predicates are defined. 97 | 98 | \def \@eqlp #1#2{\ifnum #1 = #2\@true \else \@false \fi} 99 | \def \@neqlp #1#2{\ifnum #1 = #2\@false \else \@true \fi} 100 | \def \@lssp #1#2{\ifnum #1 < #2\@true \else \@false \fi} 101 | \def \@gtrp #1#2{\ifnum #1 > #2\@true \else \@false \fi} 102 | \def \@zerop #1{\ifnum #1 = 0\@true \else \@false \fi} 103 | \def \@onep #1{\ifnum #1 = 1\@true \else \@false \fi} 104 | \def \@posp #1{\ifnum #1 > 0\@true \else \@false \fi} 105 | \def \@negp #1{\ifnum #1 < 0\@true \else \@false \fi} 106 | \def \@oddp #1{\ifodd #1\@true \else \@false \fi} 107 | \def \@evenp #1{\ifodd #1\@false \else \@true \fi} 108 | \def \@rangep #1#2#3{\if \@orp{\@lssp{#1}{#2}}{\@gtrp{#1}{#3}}\@false \else 109 | \@true \fi} 110 | \def \@tensp #1{\@rangep{#1}{10}{19}} 111 | 112 | \def \@dimeqlp #1#2{\ifdim #1 = #2\@true \else \@false \fi} 113 | \def \@dimneqlp #1#2{\ifdim #1 = #2\@false \else \@true \fi} 114 | \def \@dimlssp #1#2{\ifdim #1 < #2\@true \else \@false \fi} 115 | \def \@dimgtrp #1#2{\ifdim #1 > #2\@true \else \@false \fi} 116 | \def \@dimzerop #1{\ifdim #1 = 0pt\@true \else \@false \fi} 117 | \def \@dimposp #1{\ifdim #1 > 0pt\@true \else \@false \fi} 118 | \def \@dimnegp #1{\ifdim #1 < 0pt\@true \else \@false \fi} 119 | 120 | \def \@vmodep {\ifvmode \@true \else \@false \fi} 121 | \def \@hmodep {\ifhmode \@true \else \@false \fi} 122 | \def \@mathmodep {\ifmmode \@true \else \@false \fi} 123 | \def \@textmodep {\ifmmode \@false \else \@true \fi} 124 | \def \@innermodep {\ifinner \@true \else \@false \fi} 125 | 126 | \long\def \@codeeqlp #1#2{\if #1#2\@true \else \@false \fi} 127 | 128 | \long\def \@cateqlp #1#2{\ifcat #1#2\@true \else \@false \fi} 129 | 130 | \long\def \@tokeqlp #1#2{\ifx #1#2\@true \else \@false \fi} 131 | \long\def \@xtokeqlp #1#2{\expandafter\ifx #1#2\@true \else \@false \fi} 132 | 133 | \long\def \@definedp #1{% 134 | \expandafter\ifx \csname \expandafter\@discardtok \string#1\endcsname 135 | \relax \@false \else \@true \fi} 136 | 137 | \long\def \@undefinedp #1{% 138 | \expandafter\ifx \csname \expandafter\@discardtok \string#1\endcsname 139 | \relax \@true \else \@false \fi} 140 | 141 | \def \@emptydefp #1{\ifx #1\@empty \@true \else \@false \fi}% {\name} 142 | 143 | \let \@emptylistp = \@emptydefp 144 | 145 | \long\def \@emptyargp #1{% {#n} 146 | \@empargp #1\@empargq\@mark} 147 | \long\def \@empargp #1#2\@mark{% 148 | \ifx #1\@empargq \@true \else \@false \fi} 149 | \def \@empargq {\@empargq} 150 | 151 | \def \@emptytoksp #1{% {\tokenreg} 152 | \expandafter\@emptoksp \the#1\@mark} 153 | 154 | \long\def \@emptoksp #1\@mark{\@emptyargp{#1}} 155 | 156 | \def \@voidboxp #1{\ifvoid #1\@true \else \@false \fi} 157 | \def \@hboxp #1{\ifhbox #1\@true \else \@false \fi} 158 | \def \@vboxp #1{\ifvbox #1\@true \else \@false \fi} 159 | 160 | \def \@eofp #1{\ifeof #1\@true \else \@false \fi} 161 | 162 | 163 | % Flags can also be used as predicates, as in: 164 | % 165 | % \if \flaga \else \fi 166 | 167 | 168 | % Now here we have predicates for the common logical operators. 169 | 170 | \def \@notp #1{\if #1\@false \else \@true \fi} 171 | 172 | \def \@andp #1#2{\if #1% 173 | \if #2\@true \else \@false \fi 174 | \else 175 | \@false 176 | \fi} 177 | 178 | \def \@orp #1#2{\if #1% 179 | \@true 180 | \else 181 | \if #2\@true \else \@false \fi 182 | \fi} 183 | 184 | \def \@xorp #1#2{\if #1% 185 | \if #2\@false \else \@true \fi 186 | \else 187 | \if #2\@true \else \@false \fi 188 | \fi} 189 | 190 | % Arithmetic 191 | % ---------- 192 | 193 | \def \@increment #1{\advance #1 by 1\relax}% {\count} 194 | 195 | \def \@decrement #1{\advance #1 by -1\relax}% {\count} 196 | 197 | % Options 198 | % ------- 199 | 200 | 201 | \@setflag \@authoryear = \@false 202 | \@setflag \@blockstyle = \@false 203 | \@setflag \@copyrightwanted = \@true 204 | \@setflag \@explicitsize = \@false 205 | \@setflag \@mathtime = \@false 206 | \@setflag \@natbib = \@true 207 | \@setflag \@ninepoint = \@true 208 | \newcount{\@numheaddepth} \@numheaddepth = 3 209 | \@setflag \@onecolumn = \@false 210 | \@setflag \@preprint = \@false 211 | \@setflag \@reprint = \@false 212 | \@setflag \@tenpoint = \@false 213 | \@setflag \@times = \@false 214 | 215 | % Note that all the dangerous article class options are trapped. 216 | 217 | \DeclareOption{9pt}{\@setflag \@ninepoint = \@true 218 | \@setflag \@explicitsize = \@true} 219 | 220 | \DeclareOption{10pt}{\PassOptionsToClass{10pt}{article}% 221 | \@setflag \@ninepoint = \@false 222 | \@setflag \@tenpoint = \@true 223 | \@setflag \@explicitsize = \@true} 224 | 225 | \DeclareOption{11pt}{\PassOptionsToClass{11pt}{article}% 226 | \@setflag \@ninepoint = \@false 227 | \@setflag \@explicitsize = \@true} 228 | 229 | \DeclareOption{12pt}{\@unsupportedoption{12pt}} 230 | 231 | \DeclareOption{a4paper}{\@unsupportedoption{a4paper}} 232 | 233 | \DeclareOption{a5paper}{\@unsupportedoption{a5paper}} 234 | 235 | \DeclareOption{authoryear}{\@setflag \@authoryear = \@true} 236 | 237 | \DeclareOption{b5paper}{\@unsupportedoption{b5paper}} 238 | 239 | \DeclareOption{blockstyle}{\@setflag \@blockstyle = \@true} 240 | 241 | \DeclareOption{cm}{\@setflag \@times = \@false} 242 | 243 | \DeclareOption{computermodern}{\@setflag \@times = \@false} 244 | 245 | \DeclareOption{executivepaper}{\@unsupportedoption{executivepaper}} 246 | 247 | \DeclareOption{indentedstyle}{\@setflag \@blockstyle = \@false} 248 | 249 | \DeclareOption{landscape}{\@unsupportedoption{landscape}} 250 | 251 | \DeclareOption{legalpaper}{\@unsupportedoption{legalpaper}} 252 | 253 | \DeclareOption{letterpaper}{\@unsupportedoption{letterpaper}} 254 | 255 | \DeclareOption{mathtime}{\@setflag \@mathtime = \@true} 256 | 257 | \DeclareOption{natbib}{\@setflag \@natbib = \@true} 258 | 259 | \DeclareOption{nonatbib}{\@setflag \@natbib = \@false} 260 | 261 | \DeclareOption{nocopyrightspace}{\@setflag \@copyrightwanted = \@false} 262 | 263 | \DeclareOption{notitlepage}{\@unsupportedoption{notitlepage}} 264 | 265 | \DeclareOption{numberedpars}{\@numheaddepth = 4} 266 | 267 | \DeclareOption{numbers}{\@setflag \@authoryear = \@false} 268 | 269 | %%%\DeclareOption{onecolumn}{\@setflag \@onecolumn = \@true} 270 | 271 | \DeclareOption{preprint}{\@setflag \@preprint = \@true} 272 | 273 | \DeclareOption{reprint}{\@setflag \@reprint = \@true} 274 | 275 | \DeclareOption{times}{\@setflag \@times = \@true} 276 | 277 | \DeclareOption{titlepage}{\@unsupportedoption{titlepage}} 278 | 279 | \DeclareOption{twocolumn}{\@setflag \@onecolumn = \@false} 280 | 281 | \DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}} 282 | 283 | \ExecuteOptions{9pt,indentedstyle,times} 284 | \@setflag \@explicitsize = \@false 285 | \ProcessOptions 286 | 287 | \if \@onecolumn 288 | \if \@notp{\@explicitsize}% 289 | \@setflag \@ninepoint = \@false 290 | \PassOptionsToClass{11pt}{article}% 291 | \fi 292 | \PassOptionsToClass{twoside,onecolumn}{article} 293 | \else 294 | \PassOptionsToClass{twoside,twocolumn}{article} 295 | \fi 296 | \LoadClass{article} 297 | 298 | \def \@unsupportedoption #1{% 299 | \ClassError{proc}{The standard '#1' option is not supported.}} 300 | 301 | % This can be used with the 'reprint' option to get the final folios. 302 | 303 | \def \setpagenumber #1{% 304 | \setcounter{page}{#1}} 305 | 306 | \AtEndDocument{\label{sigplanconf@finalpage}} 307 | 308 | % Utilities 309 | % --------- 310 | 311 | 312 | \newcommand{\setvspace}[2]{% 313 | #1 = #2 314 | \advance #1 by -1\parskip} 315 | 316 | % Document Parameters 317 | % -------- ---------- 318 | 319 | 320 | % Page: 321 | 322 | \setlength{\hoffset}{-1in} 323 | \setlength{\voffset}{-1in} 324 | 325 | \setlength{\topmargin}{1in} 326 | \setlength{\headheight}{0pt} 327 | \setlength{\headsep}{0pt} 328 | 329 | \if \@onecolumn 330 | \setlength{\evensidemargin}{.75in} 331 | \setlength{\oddsidemargin}{.75in} 332 | \else 333 | \setlength{\evensidemargin}{.75in} 334 | \setlength{\oddsidemargin}{.75in} 335 | \fi 336 | 337 | % Text area: 338 | 339 | \newdimen{\standardtextwidth} 340 | \setlength{\standardtextwidth}{42pc} 341 | 342 | \if \@onecolumn 343 | \setlength{\textwidth}{40.5pc} 344 | \else 345 | \setlength{\textwidth}{\standardtextwidth} 346 | \fi 347 | 348 | \setlength{\topskip}{8pt} 349 | \setlength{\columnsep}{2pc} 350 | \setlength{\textheight}{54.5pc} 351 | 352 | % Running foot: 353 | 354 | \setlength{\footskip}{30pt} 355 | 356 | % Paragraphs: 357 | 358 | \if \@blockstyle 359 | \setlength{\parskip}{5pt plus .1pt minus .5pt} 360 | \setlength{\parindent}{0pt} 361 | \else 362 | \setlength{\parskip}{0pt} 363 | \setlength{\parindent}{12pt} 364 | \fi 365 | 366 | \setlength{\lineskip}{.5pt} 367 | \setlength{\lineskiplimit}{\lineskip} 368 | 369 | \frenchspacing 370 | \pretolerance = 400 371 | \tolerance = \pretolerance 372 | \setlength{\emergencystretch}{5pt} 373 | \clubpenalty = 10000 374 | \widowpenalty = 10000 375 | \setlength{\hfuzz}{.5pt} 376 | 377 | % Standard vertical spaces: 378 | 379 | \newskip{\standardvspace} 380 | \setvspace{\standardvspace}{5pt plus 1pt minus .5pt} 381 | 382 | % Margin paragraphs: 383 | 384 | \setlength{\marginparwidth}{36pt} 385 | \setlength{\marginparsep}{2pt} 386 | \setlength{\marginparpush}{8pt} 387 | 388 | 389 | \setlength{\skip\footins}{8pt plus 3pt minus 1pt} 390 | \setlength{\footnotesep}{9pt} 391 | 392 | \renewcommand{\footnoterule}{% 393 | \hrule width .5\columnwidth height .33pt depth 0pt} 394 | 395 | \renewcommand{\@makefntext}[1]{% 396 | \noindent \@makefnmark \hspace{1pt}#1} 397 | 398 | % Floats: 399 | 400 | \setcounter{topnumber}{4} 401 | \setcounter{bottomnumber}{1} 402 | \setcounter{totalnumber}{4} 403 | 404 | \renewcommand{\fps@figure}{tp} 405 | \renewcommand{\fps@table}{tp} 406 | \renewcommand{\topfraction}{0.90} 407 | \renewcommand{\bottomfraction}{0.30} 408 | \renewcommand{\textfraction}{0.10} 409 | \renewcommand{\floatpagefraction}{0.75} 410 | 411 | \setcounter{dbltopnumber}{4} 412 | 413 | \renewcommand{\dbltopfraction}{\topfraction} 414 | \renewcommand{\dblfloatpagefraction}{\floatpagefraction} 415 | 416 | \setlength{\floatsep}{18pt plus 4pt minus 2pt} 417 | \setlength{\textfloatsep}{18pt plus 4pt minus 3pt} 418 | \setlength{\intextsep}{10pt plus 4pt minus 3pt} 419 | 420 | \setlength{\dblfloatsep}{18pt plus 4pt minus 2pt} 421 | \setlength{\dbltextfloatsep}{20pt plus 4pt minus 3pt} 422 | 423 | % Miscellaneous: 424 | 425 | \errorcontextlines = 5 426 | 427 | % Fonts 428 | % ----- 429 | 430 | 431 | \if \@times 432 | \renewcommand{\rmdefault}{ptm}% 433 | \if \@mathtime 434 | \usepackage[mtbold,noTS1]{mathtime}% 435 | \else 436 | %%% \usepackage{mathptm}% 437 | \fi 438 | \else 439 | \relax 440 | \fi 441 | 442 | \if \@ninepoint 443 | 444 | \renewcommand{\normalsize}{% 445 | \@setfontsize{\normalsize}{9pt}{10pt}% 446 | \setlength{\abovedisplayskip}{5pt plus 1pt minus .5pt}% 447 | \setlength{\belowdisplayskip}{\abovedisplayskip}% 448 | \setlength{\abovedisplayshortskip}{3pt plus 1pt minus 2pt}% 449 | \setlength{\belowdisplayshortskip}{\abovedisplayshortskip}} 450 | 451 | \renewcommand{\tiny}{\@setfontsize{\tiny}{5pt}{6pt}} 452 | 453 | \renewcommand{\scriptsize}{\@setfontsize{\scriptsize}{7pt}{8pt}} 454 | 455 | \renewcommand{\small}{% 456 | \@setfontsize{\small}{8pt}{9pt}% 457 | \setlength{\abovedisplayskip}{4pt plus 1pt minus 1pt}% 458 | \setlength{\belowdisplayskip}{\abovedisplayskip}% 459 | \setlength{\abovedisplayshortskip}{2pt plus 1pt}% 460 | \setlength{\belowdisplayshortskip}{\abovedisplayshortskip}} 461 | 462 | \renewcommand{\footnotesize}{% 463 | \@setfontsize{\footnotesize}{8pt}{9pt}% 464 | \setlength{\abovedisplayskip}{4pt plus 1pt minus .5pt}% 465 | \setlength{\belowdisplayskip}{\abovedisplayskip}% 466 | \setlength{\abovedisplayshortskip}{2pt plus 1pt}% 467 | \setlength{\belowdisplayshortskip}{\abovedisplayshortskip}} 468 | 469 | \renewcommand{\large}{\@setfontsize{\large}{11pt}{13pt}} 470 | 471 | \renewcommand{\Large}{\@setfontsize{\Large}{14pt}{18pt}} 472 | 473 | \renewcommand{\LARGE}{\@setfontsize{\LARGE}{18pt}{20pt}} 474 | 475 | \renewcommand{\huge}{\@setfontsize{\huge}{20pt}{25pt}} 476 | 477 | \renewcommand{\Huge}{\@setfontsize{\Huge}{25pt}{30pt}} 478 | 479 | \else\if \@tenpoint 480 | 481 | \relax 482 | 483 | \else 484 | 485 | \relax 486 | 487 | \fi\fi 488 | 489 | % Abstract 490 | % -------- 491 | 492 | 493 | \renewenvironment{abstract}{% 494 | \section*{Abstract}% 495 | \normalsize}{% 496 | } 497 | 498 | % Bibliography 499 | % ------------ 500 | 501 | 502 | \renewenvironment{thebibliography}[1] 503 | {\section*{\refname 504 | \@mkboth{\MakeUppercase\refname}{\MakeUppercase\refname}}% 505 | \list{\@biblabel{\@arabic\c@enumiv}}% 506 | {\settowidth\labelwidth{\@biblabel{#1}}% 507 | \leftmargin\labelwidth 508 | \advance\leftmargin\labelsep 509 | \@openbib@code 510 | \usecounter{enumiv}% 511 | \let\p@enumiv\@empty 512 | \renewcommand\theenumiv{\@arabic\c@enumiv}}% 513 | \bibfont 514 | \clubpenalty4000 515 | \@clubpenalty \clubpenalty 516 | \widowpenalty4000% 517 | \sfcode`\.\@m} 518 | {\def\@noitemerr 519 | {\@latex@warning{Empty `thebibliography' environment}}% 520 | \endlist} 521 | 522 | \if \@natbib 523 | 524 | \if \@authoryear 525 | \typeout{Using natbib package with 'authoryear' citation style.} 526 | \usepackage[authoryear,square]{natbib} 527 | \bibpunct{(}{)}{;}{a}{}{,} % Change fences to parentheses; 528 | % citation separator to semicolon; 529 | % eliminate comma between author and year. 530 | \let \cite = \citep 531 | \else 532 | \typeout{Using natbib package with 'numbers' citation style.} 533 | \usepackage[numbers,sort&compress,square]{natbib} 534 | \fi 535 | \setlength{\bibsep}{3pt plus .5pt minus .25pt} 536 | 537 | \fi 538 | 539 | \def \bibfont {\small} 540 | 541 | % Categories 542 | % ---------- 543 | 544 | 545 | \@setflag \@firstcategory = \@true 546 | 547 | \newcommand{\category}[3]{% 548 | \if \@firstcategory 549 | \paragraph*{Categories and Subject Descriptors}% 550 | \@setflag \@firstcategory = \@false 551 | \else 552 | \unskip ;\hspace{.75em}% 553 | \fi 554 | \@ifnextchar [{\@category{#1}{#2}{#3}}{\@category{#1}{#2}{#3}[]}} 555 | 556 | \def \@category #1#2#3[#4]{% 557 | {\let \and = \relax 558 | #1 [\textit{#2}]% 559 | \if \@emptyargp{#4}% 560 | \if \@notp{\@emptyargp{#3}}: #3\fi 561 | \else 562 | :\space 563 | \if \@notp{\@emptyargp{#3}}#3---\fi 564 | \textrm{#4}% 565 | \fi}} 566 | 567 | % Copyright Notice 568 | % --------- ------ 569 | 570 | 571 | \def \ftype@copyrightbox {8} 572 | \def \@toappear {} 573 | \def \@permission {} 574 | \def \@reprintprice {} 575 | 576 | \def \@copyrightspace {% 577 | %\@float{copyrightbox}[b]% 578 | %\vbox to 1.2in{% 579 | % \vfill 580 | % \parbox[b]{20pc}{% 581 | % \scriptsize 582 | % \if \@preprint 583 | % [Copyright notice will appear here 584 | % once 'preprint' option is removed.]\par 585 | % \else 586 | % \@toappear 587 | % \fi 588 | % \if \@reprint 589 | % \noindent Reprinted from \@conferencename, 590 | % \@proceedings, 591 | % \@conferenceinfo, 592 | % pp.~\number\thepage--\pageref{sigplanconf@finalpage}.\par 593 | % \fi}}% 594 | %\end@float 595 | } 596 | 597 | \newcommand{\reprintprice}[1]{% 598 | \gdef \@reprintprice {#1}} 599 | 600 | \reprintprice{\$15.00} 601 | 602 | \long\def \toappear #1{% 603 | \def \@toappear {#1}} 604 | 605 | \toappear{% 606 | %\noindent \@permission \par 607 | %\vspace{2pt} 608 | %\noindent \textsl{\@conferencename}, \quad \@conferenceinfo. \par 609 | %\noindent Copyright \copyright\ \@copyrightyear\ ACM \@copyrightdata 610 | % \dots \@reprintprice.\par 611 | %\noindent http://dx.doi.org/10.1145/\@doi 612 | } 613 | 614 | \newcommand{\permission}[1]{% 615 | \gdef \@permission {#1}} 616 | 617 | \permission{% 618 | % Permission to make digital or hard copies of all or part of this work for 619 | % personal or classroom use is granted without fee provided that copies are 620 | % not made or distributed for profit or commercial advantage and that copies 621 | % bear this notice and the full citation on the first page. Copyrights for 622 | % components of this work owned by others than ACM must be honored. 623 | % Abstracting with credit is permitted. To copy otherwise, or republish, to 624 | % post on servers or to redistribute to lists, requires prior specific 625 | % permission and/or a fee. Request permissions from permissions@acm.org. 626 | } 627 | 628 | % These are two new rights management and bibstrip text blocks. 629 | 630 | \newcommand{\exclusivelicense}{% 631 | \permission{% 632 | Permission to make digital or hard copies of all or part of this work for 633 | personal or classroom use is granted without fee provided that copies are 634 | not made or distributed for profit or commercial advantage and that copies 635 | bear this notice and the full citation on the first page. Copyrights for 636 | components of this work owned by others than the author(s) must be honored. 637 | Abstracting with credit is permitted. To copy otherwise, or republish, to 638 | post on servers or to redistribute to lists, requires prior specific 639 | permission and/or a fee. Request permissions from permissions@acm.org.} 640 | \toappear{% 641 | \noindent \@permission \par 642 | \vspace{2pt} 643 | \noindent \textsl{\@conferencename}, \quad \@conferenceinfo. \par 644 | \noindent Copyright is held by the owner/author(s). Publication rights licensed to ACM. \par 645 | \noindent ACM \@copyrightdata \dots \@reprintprice.\par 646 | \noindent http://dx.doi.org/10.1145/\@doi}} 647 | 648 | \newcommand{\permissiontopublish}{% 649 | \permission{% 650 | Permission to make digital or hard copies of part or all of this work for 651 | personal or classroom use is granted without fee provided that copies are 652 | not made or distributed for profit or commercial advantage and that copies 653 | bear this notice and the full citation on the first page. Copyrights for 654 | third-party components of this work must be honored. 655 | For all other uses, contact the owner/author(s).}% 656 | \toappear{% 657 | \noindent \@permission \par 658 | \vspace{2pt} 659 | \noindent \textsl{\@conferencename}, \quad \@conferenceinfo. \par 660 | \noindent Copyright is held by the owner/author(s). \par 661 | \noindent ACM \@copyrightdata.\par 662 | \noindent http://dx.doi.org/10.1145/\@doi}} 663 | 664 | % The following permission notices are 665 | % for the traditional copyright transfer agreement option. 666 | 667 | % Exclusive license and permission-to-publish 668 | % give more complicated permission notices. 669 | % These are not covered here. 670 | 671 | \newcommand{\ACMCanadapermission}{% 672 | \permission{% 673 | ACM acknowledges that this contribution was authored or 674 | co-authored by an affiliate of the Canadian National 675 | Government. As such, the Crown in Right of Canada retains an equal 676 | interest in the copyright. Reprint requests should be forwarded to 677 | ACM.}} 678 | 679 | \newcommand{\ACMUSpermission}{% 680 | \permission{% 681 | ACM acknowledges that this contribution was authored or 682 | co-authored by a contractor or affiliate of the United States 683 | Government. As such, the United States Government retains a 684 | nonexclusive, royalty-free right to publish or reproduce this 685 | article, or to allow others to do so, for Government purposes 686 | only.}} 687 | 688 | \newcommand{\USpublicpermission}{% 689 | \permission{% 690 | This paper is authored by an employee(s) of the United States 691 | Government and is in the public domain. Non-exclusive copying or 692 | redistribution is allowed, provided that the article citation is 693 | given and the authors and the agency are clearly identified as its 694 | source.}% 695 | \toappear{% 696 | \noindent \@permission \par 697 | \vspace{2pt} 698 | \noindent \textsl{\@conferencename}, \quad \@conferenceinfo. \par 699 | \noindent ACM \@copyrightdata.\par 700 | \noindent http://dx.doi.org/10.1145/\@doi}} 701 | 702 | \newcommand{\authorversion}[4]{% 703 | \permission{% 704 | Copyright \copyright\ ACM, #1. This is the author's version of the work. 705 | It is posted here by permission of ACM for your personal use. 706 | Not for redistribution. The definitive version was published in 707 | #2, #3, http://dx.doi.org/10.1145/#4.}} 708 | 709 | % Enunciations 710 | % ------------ 711 | 712 | 713 | \def \@begintheorem #1#2{% {name}{number} 714 | \trivlist 715 | \item[\hskip \labelsep \textsc{#1 #2.}]% 716 | \itshape\selectfont 717 | \ignorespaces} 718 | 719 | \def \@opargbegintheorem #1#2#3{% {name}{number}{title} 720 | \trivlist 721 | \item[% 722 | \hskip\labelsep \textsc{#1\ #2}% 723 | \if \@notp{\@emptyargp{#3}}\nut (#3).\fi]% 724 | \itshape\selectfont 725 | \ignorespaces} 726 | 727 | % Figures 728 | % ------- 729 | 730 | 731 | \@setflag \@caprule = \@true 732 | 733 | \long\def \@makecaption #1#2{% 734 | \addvspace{4pt} 735 | \if \@caprule 736 | \hrule width \hsize height .33pt 737 | \vspace{4pt} 738 | \fi 739 | \setbox \@tempboxa = \hbox{\@setfigurenumber{#1.}\nut #2}% 740 | \if \@dimgtrp{\wd\@tempboxa}{\hsize}% 741 | \noindent \@setfigurenumber{#1.}\nut #2\par 742 | \else 743 | \centerline{\box\@tempboxa}% 744 | \fi} 745 | 746 | \newcommand{\nocaptionrule}{% 747 | \@setflag \@caprule = \@false} 748 | 749 | \def \@setfigurenumber #1{% 750 | {\rmfamily \bfseries \selectfont #1}} 751 | 752 | % Hierarchy 753 | % --------- 754 | 755 | 756 | \setcounter{secnumdepth}{\@numheaddepth} 757 | 758 | \newskip{\@sectionaboveskip} 759 | \setvspace{\@sectionaboveskip}{10pt plus 3pt minus 2pt} 760 | 761 | \newskip{\@sectionbelowskip} 762 | \if \@blockstyle 763 | \setlength{\@sectionbelowskip}{0.1pt}% 764 | \else 765 | \setlength{\@sectionbelowskip}{4pt}% 766 | \fi 767 | 768 | \renewcommand{\section}{% 769 | \@startsection 770 | {section}% 771 | {1}% 772 | {0pt}% 773 | {-\@sectionaboveskip}% 774 | {\@sectionbelowskip}% 775 | {\large \bfseries \raggedright}} 776 | 777 | \newskip{\@subsectionaboveskip} 778 | \setvspace{\@subsectionaboveskip}{8pt plus 2pt minus 2pt} 779 | 780 | \newskip{\@subsectionbelowskip} 781 | \if \@blockstyle 782 | \setlength{\@subsectionbelowskip}{0.1pt}% 783 | \else 784 | \setlength{\@subsectionbelowskip}{4pt}% 785 | \fi 786 | 787 | \renewcommand{\subsection}{% 788 | \@startsection% 789 | {subsection}% 790 | {2}% 791 | {0pt}% 792 | {-\@subsectionaboveskip}% 793 | {\@subsectionbelowskip}% 794 | {\normalsize \bfseries \raggedright}} 795 | 796 | \renewcommand{\subsubsection}{% 797 | \@startsection% 798 | {subsubsection}% 799 | {3}% 800 | {0pt}% 801 | {-\@subsectionaboveskip} 802 | {\@subsectionbelowskip}% 803 | {\normalsize \bfseries \raggedright}} 804 | 805 | \newskip{\@paragraphaboveskip} 806 | \setvspace{\@paragraphaboveskip}{6pt plus 2pt minus 2pt} 807 | 808 | \renewcommand{\paragraph}{% 809 | \@startsection% 810 | {paragraph}% 811 | {4}% 812 | {0pt}% 813 | {\@paragraphaboveskip} 814 | {-1em}% 815 | {\normalsize \bfseries \if \@times \itshape \fi}} 816 | 817 | \renewcommand{\subparagraph}{% 818 | \@startsection% 819 | {subparagraph}% 820 | {4}% 821 | {0pt}% 822 | {\@paragraphaboveskip} 823 | {-1em}% 824 | {\normalsize \itshape}} 825 | 826 | % Standard headings: 827 | 828 | \newcommand{\acks}{\section*{Acknowledgments}} 829 | 830 | \newcommand{\keywords}{\paragraph*{Keywords}} 831 | 832 | \newcommand{\terms}{\paragraph*{General Terms}} 833 | 834 | % Identification 835 | % -------------- 836 | 837 | 838 | \def \@conferencename {} 839 | \def \@conferenceinfo {} 840 | \def \@copyrightyear {} 841 | \def \@copyrightdata {[to be supplied]} 842 | \def \@proceedings {[Unknown Proceedings]} 843 | 844 | 845 | \newcommand{\conferenceinfo}[2]{% 846 | \gdef \@conferencename {#1}% 847 | \gdef \@conferenceinfo {#2}} 848 | 849 | \newcommand{\copyrightyear}[1]{% 850 | \gdef \@copyrightyear {#1}} 851 | 852 | \let \CopyrightYear = \copyrightyear 853 | 854 | \newcommand{\copyrightdata}[1]{% 855 | \gdef \@copyrightdata {#1}} 856 | 857 | \let \crdata = \copyrightdata 858 | 859 | \newcommand{\doi}[1]{% 860 | \gdef \@doi {#1}} 861 | 862 | \newcommand{\proceedings}[1]{% 863 | \gdef \@proceedings {#1}} 864 | 865 | % Lists 866 | % ----- 867 | 868 | 869 | \setlength{\leftmargini}{13pt} 870 | \setlength\leftmarginii{13pt} 871 | \setlength\leftmarginiii{13pt} 872 | \setlength\leftmarginiv{13pt} 873 | \setlength{\labelsep}{3.5pt} 874 | 875 | \setlength{\topsep}{\standardvspace} 876 | \if \@blockstyle 877 | \setlength{\itemsep}{1pt} 878 | \setlength{\parsep}{3pt} 879 | \else 880 | \setlength{\itemsep}{1pt} 881 | \setlength{\parsep}{3pt} 882 | \fi 883 | 884 | \renewcommand{\labelitemi}{{\small \centeroncapheight{\textbullet}}} 885 | \renewcommand{\labelitemii}{\centeroncapheight{\rule{2.5pt}{2.5pt}}} 886 | \renewcommand{\labelitemiii}{$-$} 887 | \renewcommand{\labelitemiv}{{\Large \textperiodcentered}} 888 | 889 | \renewcommand{\@listi}{% 890 | \leftmargin = \leftmargini 891 | \listparindent = 0pt} 892 | %%% \itemsep = 1pt 893 | %%% \parsep = 3pt} 894 | %%% \listparindent = \parindent} 895 | 896 | \let \@listI = \@listi 897 | 898 | \renewcommand{\@listii}{% 899 | \leftmargin = \leftmarginii 900 | \topsep = 1pt 901 | \labelwidth = \leftmarginii 902 | \advance \labelwidth by -\labelsep 903 | \listparindent = \parindent} 904 | 905 | \renewcommand{\@listiii}{% 906 | \leftmargin = \leftmarginiii 907 | \labelwidth = \leftmarginiii 908 | \advance \labelwidth by -\labelsep 909 | \listparindent = \parindent} 910 | 911 | \renewcommand{\@listiv}{% 912 | \leftmargin = \leftmarginiv 913 | \labelwidth = \leftmarginiv 914 | \advance \labelwidth by -\labelsep 915 | \listparindent = \parindent} 916 | 917 | % Mathematics 918 | % ----------- 919 | 920 | 921 | \def \theequation {\arabic{equation}} 922 | 923 | % Miscellaneous 924 | % ------------- 925 | 926 | 927 | \newcommand{\balancecolumns}{% 928 | \vfill\eject 929 | \global\@colht = \textheight 930 | \global\ht\@cclv = \textheight} 931 | 932 | \newcommand{\nut}{\hspace{.5em}} 933 | 934 | \newcommand{\softraggedright}{% 935 | \let \\ = \@centercr 936 | \leftskip = 0pt 937 | \rightskip = 0pt plus 10pt} 938 | 939 | % Program Code 940 | % ------- ---- 941 | 942 | 943 | \newcommand{\mono}[1]{% 944 | {\@tempdima = \fontdimen2\font 945 | \texttt{\spaceskip = 1.1\@tempdima #1}}} 946 | 947 | % Running Heads and Feet 948 | % ------- ----- --- ---- 949 | 950 | 951 | \def \@preprintfooter {} 952 | 953 | \newcommand{\preprintfooter}[1]{% 954 | \gdef \@preprintfooter {#1}} 955 | 956 | \if \@preprint 957 | 958 | \def \ps@plain {% 959 | \let \@mkboth = \@gobbletwo 960 | \let \@evenhead = \@empty 961 | \def \@evenfoot {\scriptsize 962 | \rlap{\textit{\@preprintfooter}}\hfil 963 | \thepage \hfil 964 | \llap{\textit{\@formatyear}}}% 965 | \let \@oddhead = \@empty 966 | \let \@oddfoot = \@evenfoot} 967 | 968 | \else\if \@reprint 969 | 970 | \def \ps@plain {% 971 | \let \@mkboth = \@gobbletwo 972 | \let \@evenhead = \@empty 973 | \def \@evenfoot {\scriptsize \hfil \thepage \hfil}% 974 | \let \@oddhead = \@empty 975 | \let \@oddfoot = \@evenfoot} 976 | 977 | \else 978 | 979 | \let \ps@plain = \ps@empty 980 | \let \ps@headings = \ps@empty 981 | \let \ps@myheadings = \ps@empty 982 | 983 | \fi\fi 984 | 985 | \def \@formatyear {% 986 | \number\year/\number\month/\number\day} 987 | 988 | % Special Characters 989 | % ------- ---------- 990 | 991 | 992 | \DeclareRobustCommand{\euro}{% 993 | \protect{\rlap{=}}{\sf \kern .1em C}} 994 | 995 | % Title Page 996 | % ----- ---- 997 | 998 | 999 | \@setflag \@addauthorsdone = \@false 1000 | 1001 | \def \@titletext {\@latex@error{No title was provided}{}} 1002 | \def \@subtitletext {} 1003 | 1004 | \newcount{\@authorcount} 1005 | 1006 | \newcount{\@titlenotecount} 1007 | \newtoks{\@titlenotetext} 1008 | 1009 | \def \@titlebanner {} 1010 | 1011 | \renewcommand{\title}[1]{% 1012 | \gdef \@titletext {#1}} 1013 | 1014 | \newcommand{\subtitle}[1]{% 1015 | \gdef \@subtitletext {#1}} 1016 | 1017 | \newcommand{\authorinfo}[3]{% {names}{affiliation}{email/URL} 1018 | \global\@increment \@authorcount 1019 | \@withname\gdef {\@authorname\romannumeral\@authorcount}{#1}% 1020 | \@withname\gdef {\@authoraffil\romannumeral\@authorcount}{#2}% 1021 | \@withname\gdef {\@authoremail\romannumeral\@authorcount}{#3}} 1022 | 1023 | \renewcommand{\author}[1]{% 1024 | \@latex@error{The \string\author\space command is obsolete; 1025 | use \string\authorinfo}{}} 1026 | 1027 | \newcommand{\titlebanner}[1]{% 1028 | \gdef \@titlebanner {#1}} 1029 | 1030 | \renewcommand{\maketitle}{% 1031 | \pagestyle{plain}% 1032 | \if \@onecolumn 1033 | {\hsize = \standardtextwidth 1034 | \@maketitle}% 1035 | \else 1036 | \twocolumn[\@maketitle]% 1037 | \fi 1038 | \@placetitlenotes 1039 | \if \@copyrightwanted \@copyrightspace \fi} 1040 | 1041 | \def \@maketitle {% 1042 | \begin{center} 1043 | \@settitlebanner 1044 | \let \thanks = \titlenote 1045 | {\leftskip = 0pt plus 0.25\linewidth 1046 | \rightskip = 0pt plus 0.25 \linewidth 1047 | \parfillskip = 0pt 1048 | \spaceskip = .7em 1049 | \noindent \LARGE \bfseries \@titletext \par} 1050 | \vskip 6pt 1051 | \noindent \Large \@subtitletext \par 1052 | \vskip 12pt 1053 | \ifcase \@authorcount 1054 | \@latex@error{No authors were specified for this paper}{}\or 1055 | \@titleauthors{i}{}{}\or 1056 | \@titleauthors{i}{ii}{}\or 1057 | \@titleauthors{i}{ii}{iii}\or 1058 | \@titleauthors{i}{ii}{iii}\@titleauthors{iv}{}{}\or 1059 | \@titleauthors{i}{ii}{iii}\@titleauthors{iv}{v}{}\or 1060 | \@titleauthors{i}{ii}{iii}\@titleauthors{iv}{v}{vi}\or 1061 | \@titleauthors{i}{ii}{iii}\@titleauthors{iv}{v}{vi}% 1062 | \@titleauthors{vii}{}{}\or 1063 | \@titleauthors{i}{ii}{iii}\@titleauthors{iv}{v}{vi}% 1064 | \@titleauthors{vii}{viii}{}\or 1065 | \@titleauthors{i}{ii}{iii}\@titleauthors{iv}{v}{vi}% 1066 | \@titleauthors{vii}{viii}{ix}\or 1067 | \@titleauthors{i}{ii}{iii}\@titleauthors{iv}{v}{vi}% 1068 | \@titleauthors{vii}{viii}{ix}\@titleauthors{x}{}{}\or 1069 | \@titleauthors{i}{ii}{iii}\@titleauthors{iv}{v}{vi}% 1070 | \@titleauthors{vii}{viii}{ix}\@titleauthors{x}{xi}{}\or 1071 | \@titleauthors{i}{ii}{iii}\@titleauthors{iv}{v}{vi}% 1072 | \@titleauthors{vii}{viii}{ix}\@titleauthors{x}{xi}{xii}% 1073 | \else 1074 | \@latex@error{Cannot handle more than 12 authors}{}% 1075 | \fi 1076 | \vspace{1.75pc} 1077 | \end{center}} 1078 | 1079 | \def \@settitlebanner {% 1080 | \if \@andp{\@preprint}{\@notp{\@emptydefp{\@titlebanner}}}% 1081 | \vbox to 0pt{% 1082 | \vskip -32pt 1083 | \noindent \textbf{\@titlebanner}\par 1084 | \vss}% 1085 | \nointerlineskip 1086 | \fi} 1087 | 1088 | \def \@titleauthors #1#2#3{% 1089 | \if \@andp{\@emptyargp{#2}}{\@emptyargp{#3}}% 1090 | \noindent \@setauthor{40pc}{#1}{\@false}\par 1091 | \else\if \@emptyargp{#3}% 1092 | \noindent \@setauthor{17pc}{#1}{\@false}\hspace{3pc}% 1093 | \@setauthor{17pc}{#2}{\@false}\par 1094 | \else 1095 | \noindent \@setauthor{12.5pc}{#1}{\@false}\hspace{2pc}% 1096 | \@setauthor{12.5pc}{#2}{\@false}\hspace{2pc}% 1097 | \@setauthor{12.5pc}{#3}{\@true}\par 1098 | \relax 1099 | \fi\fi 1100 | \vspace{20pt}} 1101 | 1102 | \def \@setauthor #1#2#3{% {width}{text}{unused} 1103 | \vtop{% 1104 | \def \and {% 1105 | \hspace{16pt}} 1106 | \hsize = #1 1107 | \normalfont 1108 | \centering 1109 | \large \@name{\@authorname#2}\par 1110 | \vspace{5pt} 1111 | \normalsize \@name{\@authoraffil#2}\par 1112 | \vspace{2pt} 1113 | \textsf{\@name{\@authoremail#2}}\par}} 1114 | 1115 | \def \@maybetitlenote #1{% 1116 | \if \@andp{#1}{\@gtrp{\@authorcount}{3}}% 1117 | \titlenote{See page~\pageref{@addauthors} for additional authors.}% 1118 | \fi} 1119 | 1120 | \newtoks{\@fnmark} 1121 | 1122 | \newcommand{\titlenote}[1]{% 1123 | \global\@increment \@titlenotecount 1124 | \ifcase \@titlenotecount \relax \or 1125 | \@fnmark = {\ast}\or 1126 | \@fnmark = {\dagger}\or 1127 | \@fnmark = {\ddagger}\or 1128 | \@fnmark = {\S}\or 1129 | \@fnmark = {\P}\or 1130 | \@fnmark = {\ast\ast}% 1131 | \fi 1132 | \,$^{\the\@fnmark}$% 1133 | \edef \reserved@a {\noexpand\@appendtotext{% 1134 | \noexpand\@titlefootnote{\the\@fnmark}}}% 1135 | \reserved@a{#1}} 1136 | 1137 | \def \@appendtotext #1#2{% 1138 | \global\@titlenotetext = \expandafter{\the\@titlenotetext #1{#2}}} 1139 | 1140 | \newcount{\@authori} 1141 | 1142 | \iffalse 1143 | \def \additionalauthors {% 1144 | \if \@gtrp{\@authorcount}{3}% 1145 | \section{Additional Authors}% 1146 | \label{@addauthors}% 1147 | \noindent 1148 | \@authori = 4 1149 | {\let \\ = ,% 1150 | \loop 1151 | \textbf{\@name{\@authorname\romannumeral\@authori}}, 1152 | \@name{\@authoraffil\romannumeral\@authori}, 1153 | email: \@name{\@authoremail\romannumeral\@authori}.% 1154 | \@increment \@authori 1155 | \if \@notp{\@gtrp{\@authori}{\@authorcount}} \repeat}% 1156 | \par 1157 | \fi 1158 | \global\@setflag \@addauthorsdone = \@true} 1159 | \fi 1160 | 1161 | \let \addauthorsection = \additionalauthors 1162 | 1163 | \def \@placetitlenotes { 1164 | \the\@titlenotetext} 1165 | 1166 | % Utilities 1167 | % --------- 1168 | 1169 | 1170 | \newcommand{\centeroncapheight}[1]{% 1171 | {\setbox\@tempboxa = \hbox{#1}% 1172 | \@measurecapheight{\@tempdima}% % Calculate ht(CAP) - ht(text) 1173 | \advance \@tempdima by -\ht\@tempboxa % ------------------ 1174 | \divide \@tempdima by 2 % 2 1175 | \raise \@tempdima \box\@tempboxa}} 1176 | 1177 | \newbox{\@measbox} 1178 | 1179 | \def \@measurecapheight #1{% {\dimen} 1180 | \setbox\@measbox = \hbox{ABCDEFGHIJKLMNOPQRSTUVWXYZ}% 1181 | #1 = \ht\@measbox} 1182 | 1183 | \long\def \@titlefootnote #1#2{% 1184 | \insert\footins{% 1185 | \reset@font\footnotesize 1186 | \interlinepenalty\interfootnotelinepenalty 1187 | \splittopskip\footnotesep 1188 | \splitmaxdepth \dp\strutbox \floatingpenalty \@MM 1189 | \hsize\columnwidth \@parboxrestore 1190 | %%% \protected@edef\@currentlabel{% 1191 | %%% \csname p@footnote\endcsname\@thefnmark}% 1192 | \color@begingroup 1193 | \def \@makefnmark {$^{#1}$}% 1194 | \@makefntext{% 1195 | \rule\z@\footnotesep\ignorespaces#2\@finalstrut\strutbox}% 1196 | \color@endgroup}} 1197 | 1198 | % LaTeX Modifications 1199 | % ----- ------------- 1200 | 1201 | \def \@seccntformat #1{% 1202 | \@name{\the#1}% 1203 | \@expandaftertwice\@seccntformata \csname the#1\endcsname.\@mark 1204 | \quad} 1205 | 1206 | \def \@seccntformata #1.#2\@mark{% 1207 | \if \@emptyargp{#2}.\fi} 1208 | 1209 | % Revision History 1210 | % -------- ------- 1211 | 1212 | 1213 | % Date Person Ver. Change 1214 | % ---- ------ ---- ------ 1215 | 1216 | % 2004.09.12 PCA 0.1--4 Preliminary development. 1217 | 1218 | % 2004.11.18 PCA 0.5 Start beta testing. 1219 | 1220 | % 2004.11.19 PCA 0.6 Obsolete \author and replace with 1221 | % \authorinfo. 1222 | % Add 'nocopyrightspace' option. 1223 | % Compress article opener spacing. 1224 | % Add 'mathtime' option. 1225 | % Increase text height by 6 points. 1226 | 1227 | % 2004.11.28 PCA 0.7 Add 'cm/computermodern' options. 1228 | % Change default to Times text. 1229 | 1230 | % 2004.12.14 PCA 0.8 Remove use of mathptm.sty; it cannot 1231 | % coexist with latexsym or amssymb. 1232 | 1233 | % 2005.01.20 PCA 0.9 Rename class file to sigplanconf.cls. 1234 | 1235 | % 2005.03.05 PCA 0.91 Change default copyright data. 1236 | 1237 | % 2005.03.06 PCA 0.92 Add at-signs to some macro names. 1238 | 1239 | % 2005.03.07 PCA 0.93 The 'onecolumn' option defaults to '11pt', 1240 | % and it uses the full type width. 1241 | 1242 | % 2005.03.15 PCA 0.94 Add at-signs to more macro names. 1243 | % Allow margin paragraphs during review. 1244 | 1245 | % 2005.03.22 PCA 0.95 Implement \euro. 1246 | % Remove proof and newdef environments. 1247 | 1248 | % 2005.05.06 PCA 1.0 Eliminate 'onecolumn' option. 1249 | % Change footer to small italic and eliminate 1250 | % left portion if no \preprintfooter. 1251 | % Eliminate copyright notice if preprint. 1252 | % Clean up and shrink copyright box. 1253 | 1254 | % 2005.05.30 PCA 1.1 Add alternate permission statements. 1255 | 1256 | % 2005.06.29 PCA 1.1 Publish final first edition of guide. 1257 | 1258 | % 2005.07.14 PCA 1.2 Add \subparagraph. 1259 | % Use block paragraphs in lists, and adjust 1260 | % spacing between items and paragraphs. 1261 | 1262 | % 2006.06.22 PCA 1.3 Add 'reprint' option and associated 1263 | % commands. 1264 | 1265 | % 2006.08.24 PCA 1.4 Fix bug in \maketitle case command. 1266 | 1267 | % 2007.03.13 PCA 1.5 The title banner only displays with the 1268 | % 'preprint' option. 1269 | 1270 | % 2007.06.06 PCA 1.6 Use \bibfont in \thebibliography. 1271 | % Add 'natbib' option to load and configure 1272 | % the natbib package. 1273 | 1274 | % 2007.11.20 PCA 1.7 Balance line lengths in centered article 1275 | % title (thanks to Norman Ramsey). 1276 | 1277 | % 2009.01.26 PCA 1.8 Change natbib \bibpunct values. 1278 | 1279 | % 2009.03.24 PCA 1.9 Change natbib to use the 'numbers' option. 1280 | % Change templates to use 'natbib' option. 1281 | 1282 | % 2009.09.01 PCA 2.0 Add \reprintprice command (suggested by 1283 | % Stephen Chong). 1284 | 1285 | % 2009.09.08 PCA 2.1 Make 'natbib' the default; add 'nonatbib'. 1286 | % SB Add 'authoryear' and 'numbers' (default) to 1287 | % control citation style when using natbib. 1288 | % Add \bibpunct to change punctuation for 1289 | % 'authoryear' style. 1290 | 1291 | % 2009.09.21 PCA 2.2 Add \softraggedright to the thebibliography 1292 | % environment. Also add to template so it will 1293 | % happen with natbib. 1294 | 1295 | % 2009.09.30 PCA 2.3 Remove \softraggedright from thebibliography. 1296 | % Just include in the template. 1297 | 1298 | % 2010.05.24 PCA 2.4 Obfuscate class author's email address. 1299 | 1300 | % 2011.11.08 PCA 2.5 Add copyright notice to this file. 1301 | % Remove 'sort' option from natbib when using 1302 | % 'authoryear' style. 1303 | % Add the \authorversion command. 1304 | 1305 | % 2013.02.22 PCA 2.6 Change natbib fences to parentheses when 1306 | % using 'authoryear' style. 1307 | 1308 | % 2013.05.17 PCA 2.7 Change standard and author copyright text. 1309 | 1310 | % 2013.07.02 TU 2.8 More changes to permission/copyright notes. 1311 | % Replaced ambiguous \authorpermission with 1312 | % \exclusivelicense and \permissiontopublish 1313 | 1314 | 1315 | --------------------------------------------------------------------------------