3 # Copyright The SCons Foundation
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 """Tool-specific initialization for yacc.
26 This tool should support multiple yacc implementations, but is in actuality
27 biased towards GNU Bison. In particular, it forces the output file name (thus
28 avoiding the default convention of y.tab.c or foo.tab.c), so the tool *must*
29 support the -o option, which pure POSIX yacc does not. byacc should be okay
30 as an alternative to bison.
32 There normally shouldn't be any need to import this module directly.
33 It will usually be imported through the generic SCons.Tool.Tool()
39 from typing
import Optional
44 from SCons
.Platform
.mingw
import MINGW_DEFAULT_PATHS
45 from SCons
.Platform
.cygwin
import CYGWIN_DEFAULT_PATHS
46 from SCons
.Platform
.win32
import CHOCO_DEFAULT_PATH
47 from SCons
.Util
import CLVar
, to_String
49 DEFAULT_PATHS
= CHOCO_DEFAULT_PATH
+ MINGW_DEFAULT_PATHS
+ CYGWIN_DEFAULT_PATHS
51 YaccAction
= SCons
.Action
.Action("$YACCCOM", "$YACCCOMSTR")
53 if sys
.platform
== 'win32':
54 BINS
= ['bison', 'yacc', 'win_bison']
56 BINS
= ["bison", "yacc", "byacc"] # for byacc, yacc is normally a link
59 def _yaccEmitter(target
, source
, env
, ysuf
, hsuf
) -> tuple:
60 """Adds extra files generated by yacc program to target list."""
62 yaccflags
= env
.subst_list("$YACCFLAGS", target
=target
, source
=source
)
64 targetBase
, targetExt
= os
.path
.splitext(to_String(target
[0]))
66 if '.ym' in ysuf
: # If using Objective-C
67 target
= [targetBase
+ ".m"] # the extension is ".m".
69 # If -d is specified on the command line, yacc will emit a .h
70 # or .hpp file with the same base name as the .c or .cpp output file.
72 # or bison options -H, --header, --defines (obsolete)
73 if "-d" in flags
or "-H" in flags
or "--header" in flags
or "--defines" in flags
:
74 target
.append(targetBase
+ env
.subst(hsuf
, target
=target
, source
=source
))
76 # If -g is specified on the command line, yacc will emit a graph
77 # file with the same base name as the .c or .cpp output file.
78 # TODO: should this be handled like -v? i.e. a side effect, not target
80 # or bison option --graph
81 if "-g" in flags
or "--graph" in flags
:
82 target
.append(targetBase
+ env
.subst("$YACC_GRAPH_FILE_SUFFIX"))
84 # If -v is specified yacc will create the output debug file
85 # which is not really source for any process, but should
86 # be noted and also be cleaned (issue #2558)
88 env
.SideEffect(targetBase
+ '.output', target
[0])
89 env
.Clean(target
[0], targetBase
+ '.output')
91 # With --defines and --graph, the file to write is defined by the option
92 # argument, if present (the no-option-argument cases were caught above).
93 # Extract this and include in the list of targets.
94 # NOTE: a filename passed to the command this way is not modified by
95 # SCons, and so will be interpreted relative to the project top directory
96 # at execution time, while the name added to the target list will be
97 # interpreted relative to the SConscript directory - a possible mismatch.
98 # Better to use YACC_HEADER_FILE and YACC_GRAPH_FILE to pass these.
100 # These are GNU bison-only options.
101 # Since bison 3.8, --header is the preferred name over --defines
102 fileGenOptions
= ["--defines=", "--header=", "--graph="]
104 for fileGenOption
in fileGenOptions
:
105 l
= len(fileGenOption
)
106 if option
[:l
] == fileGenOption
:
107 fileName
= option
[l
:].strip()
108 target
.append(fileName
)
110 yaccheaderfile
= env
.subst("$YACC_HEADER_FILE", target
=target
, source
=source
)
112 target
.append(yaccheaderfile
)
113 # rewrite user-supplied file string with a node, we need later
114 env
.Replace(YACC_HEADER_FILE
=env
.File(yaccheaderfile
))
116 yaccgraphfile
= env
.subst("$YACC_GRAPH_FILE", target
=target
, source
=source
)
118 target
.append(yaccgraphfile
)
119 # rewrite user-supplied file string with a node, we need later
120 env
.Replace(YACC_GRAPH_FILE
=env
.File(yaccgraphfile
))
122 return target
, source
125 def yEmitter(target
, source
, env
) -> tuple:
126 return _yaccEmitter(target
, source
, env
, ['.y', '.yacc'], '$YACCHFILESUFFIX')
129 def ymEmitter(target
, source
, env
) -> tuple:
130 return _yaccEmitter(target
, source
, env
, ['.ym'], '$YACCHFILESUFFIX')
133 def yyEmitter(target
, source
, env
) -> tuple:
134 return _yaccEmitter(target
, source
, env
, ['.yy'], '$YACCHXXFILESUFFIX')
137 def get_yacc_path(env
, append_paths
: bool=False) -> Optional
[str]:
139 Returns the path to the yacc tool, searching several possible names.
141 Only called in the Windows case, so the `default_path` argument to
142 :func:`find_program_path` can be Windows-specific.
145 env: current construction environment
146 append_paths: if true, add the path to the tool to PATH
149 bin_path
= SCons
.Tool
.find_program_path(
152 default_paths
=DEFAULT_PATHS
,
153 add_path
=append_paths
,
159 SCons
.Warnings
.SConsWarning
,
160 'yacc tool requested, but yacc or bison binary not found in ENV PATH'
164 def generate(env
) -> None:
165 """Add Builders and construction variables for yacc to an Environment."""
166 c_file
, cxx_file
= SCons
.Tool
.createCFileBuilders(env
)
169 c_file
.add_action('.y', YaccAction
)
170 c_file
.add_emitter('.y', yEmitter
)
172 c_file
.add_action('.yacc', YaccAction
)
173 c_file
.add_emitter('.yacc', yEmitter
)
176 c_file
.add_action('.ym', YaccAction
)
177 c_file
.add_emitter('.ym', ymEmitter
)
180 cxx_file
.add_action('.yy', YaccAction
)
181 cxx_file
.add_emitter('.yy', yyEmitter
)
183 if sys
.platform
== 'win32':
184 # ignore the return, all we need is for the path to be added
185 _
= get_yacc_path(env
, append_paths
=True)
188 YACC
=env
.Detect(BINS
),
194 env
['YACCCOM'] = '$YACC $YACCFLAGS $_YACC_HEADER $_YACC_GRAPH -o $TARGET $SOURCES'
195 env
['YACCHFILESUFFIX'] = '.h'
196 env
['YACCHXXFILESUFFIX'] = '.hpp'
197 env
['YACCVCGFILESUFFIX'] = '.gv'
198 env
['YACC_GRAPH_FILE_SUFFIX'] = '$YACCVCGFILESUFFIX'
199 env
['_YACC_HEADER'] = '${YACC_HEADER_FILE and "--header=" + str(YACC_HEADER_FILE)}'
200 env
['_YACC_GRAPH'] = '${YACC_GRAPH_FILE and "--graph=" + str(YACC_GRAPH_FILE)}'
203 def exists(env
) -> Optional
[str]:
205 return env
.Detect(env
['YACC'])
207 if sys
.platform
== 'win32':
208 return get_yacc_path(env
)
210 return env
.Detect(BINS
)
214 # indent-tabs-mode:nil
216 # vim: set expandtab tabstop=4 shiftwidth=4: