1#!/usr/bin/python
2#
3# Copyright (C) 2009 Google Inc. All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9#     * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11#     * Redistributions in binary form must reproduce the above
12# copyright notice, this list of conditions and the following disclaimer
13# in the documentation and/or other materials provided with the
14# distribution.
15#     * Neither the name of Google Inc. nor the names of its
16# contributors may be used to endorse or promote products derived from
17# this software without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30#
31# Copyright (c) 2009 The Chromium Authors. All rights reserved.
32# Use of this source code is governed by a BSD-style license that can be
33# found in the LICENSE file.
34
35# usage: rule_bison.py INPUT_FILE OUTPUT_DIR [BISON_EXE]
36# INPUT_FILE is a path to either CSSGrammar.y or XPathGrammar.y.
37# OUTPUT_DIR is where the bison-generated .cpp and .h files should be placed.
38
39import errno
40import os
41import os.path
42import subprocess
43import sys
44
45assert len(sys.argv) == 3 or len(sys.argv) == 4
46
47inputFile = sys.argv[1]
48outputDir = sys.argv[2]
49bisonExe = 'bison'
50if len(sys.argv) > 3:
51    bisonExe = sys.argv[3]
52
53pathToBison = os.path.split(bisonExe)[0]
54if pathToBison:
55    # Make sure this path is in the path so that it can find its auxiliary
56    # binaries (in particular, m4). To avoid other 'm4's being found, insert
57    # at head, rather than tail.
58    os.environ['PATH'] = pathToBison + os.pathsep + os.environ['PATH']
59
60inputName = os.path.basename(inputFile)
61assert inputName == 'CSSGrammar.y' or inputName == 'XPathGrammar.y'
62prefix = {'CSSGrammar.y': 'cssyy', 'XPathGrammar.y': 'xpathyy'}[inputName]
63
64(inputRoot, inputExt) = os.path.splitext(inputName)
65
66# The generated .h will be in a different location depending on the bison
67# version.
68outputHTries = [
69    os.path.join(outputDir, inputRoot + '.cpp.h'),
70    os.path.join(outputDir, inputRoot + '.hpp'),
71]
72
73for outputHTry in outputHTries:
74    try:
75        os.unlink(outputHTry)
76    except OSError, e:
77        if e.errno != errno.ENOENT:
78            raise
79
80outputCpp = os.path.join(outputDir, inputRoot + '.cpp')
81
82returnCode = subprocess.call([bisonExe, '-d', '-p', prefix, inputFile, '-o', outputCpp])
83assert returnCode == 0
84
85# Find the name that bison used for the generated header file.
86outputHTmp = None
87for outputHTry in outputHTries:
88    try:
89        os.stat(outputHTry)
90        outputHTmp = outputHTry
91        break
92    except OSError, e:
93        if e.errno != errno.ENOENT:
94            raise
95
96assert outputHTmp != None
97
98# Read the header file in under the generated name and remove it.
99outputHFile = open(outputHTmp)
100outputHContents = outputHFile.read()
101outputHFile.close()
102os.unlink(outputHTmp)
103
104# Rewrite the generated header with #include guards.
105outputH = os.path.join(outputDir, inputRoot + '.h')
106
107outputHFile = open(outputH, 'w')
108print >>outputHFile, '#ifndef %sH' % inputRoot
109print >>outputHFile, '#define %sH' % inputRoot
110print >>outputHFile, outputHContents
111print >>outputHFile, '#endif'
112outputHFile.close()
113