blob: ba622888617985ef40229c2a1f345fc6f68569b4 [file] [log] [blame]
YAMAMOTO Takashi6df0abb2013-07-01 17:24:04 +09001#!/usr/bin/env python
Rich Lanea06d0c32013-03-25 08:52:03 -07002# Copyright 2013, Big Switch Networks, Inc.
3#
4# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
5# the following special exception:
6#
7# LOXI Exception
8#
9# As a special exception to the terms of the EPL, you may distribute libraries
10# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
11# that copyright and licensing notices generated by LoxiGen are not altered or removed
12# from the LoxiGen Libraries and the notice provided below is (i) included in
13# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
14# documentation for the LoxiGen Libraries, if distributed in binary form.
15#
16# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
17#
18# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
19# a copy of the EPL at:
20#
21# http://www.eclipse.org/legal/epl-v10.html
22#
23# Unless required by applicable law or agreed to in writing, software
24# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
25# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
26# EPL for the specific language governing permissions and limitations
27# under the EPL.
28
29"""
30@brief
31Process openflow header files to create language specific LOXI interfaces
32
33First cut at simple python script for processing input files
34
35Internal notes
36
37An input file for each supported OpenFlow version is passed in
38on the command line.
39
40Expected input file format:
41
42These will probably be collapsed into a python dict or something
43
44The first line has the ofC version identifier and nothing else
45The second line has the openflow wire protocol value and nothing else
46
47The main content is struct elements for each OF recognized class.
48These are taken from current versions of openflow.h but are modified
49a bit. See Overview for more information.
50
Andreas Wundsam53256162013-05-02 14:05:53 -070051Class canonical form: A list of entries, each of which is a
Rich Lanea06d0c32013-03-25 08:52:03 -070052pair "type, name;". The exception is when type is the keyword
53'list' in which the syntax is "list(type) name;".
54
55From this, internal representations are generated: For each
56version, a dict indexed by class name. One element (members) is
57an array giving the member name and type. From this, wire offsets
58can be calculated.
59
60
61@fixme Clean up the lang module architecture. It should provide a
62list of files that it wants to generate and maps to the filenames,
Andreas Wundsam53256162013-05-02 14:05:53 -070063subdirectory names and generation functions. It should also be
64defined as a class, probably with the constructor taking the
Rich Lanea06d0c32013-03-25 08:52:03 -070065language target.
66
67@fixme Clean up global data structures such as versions and of_g
68structures. They should probably be a class or classes as well.
69
70"""
71
Andreas Wundsam76db0062013-11-15 13:34:41 -080072from collections import OrderedDict, defaultdict
73import copy
74import glob
75from optparse import OptionParser
76import os
Rich Lanea06d0c32013-03-25 08:52:03 -070077import re
78import string
Andreas Wundsam76db0062013-11-15 13:34:41 -080079import sys
80
81import cmdline
82from loxi_globals import OFVersions
83import loxi_globals
Rich Lanea06d0c32013-03-25 08:52:03 -070084import loxi_utils.loxi_utils as loxi_utils
Rich Lanea06d0c32013-03-25 08:52:03 -070085import pyparsing
86import loxi_front_end.parser as parser
Rich Laned47e5a22013-05-09 14:21:16 -070087import loxi_front_end.frontend as frontend
Andreas Wundsam76db0062013-11-15 13:34:41 -080088import loxi_ir
Rich Lanea06d0c32013-03-25 08:52:03 -070089from generic_utils import *
90
91root_dir = os.path.dirname(os.path.realpath(__file__))
92
Rich Lanea06d0c32013-03-25 08:52:03 -070093def process_input_file(filename):
94 """
95 Process an input file
96
Rich Laned47e5a22013-05-09 14:21:16 -070097 Does not modify global state.
98
Rich Lanea06d0c32013-03-25 08:52:03 -070099 @param filename The input filename
100
Rich Laned47e5a22013-05-09 14:21:16 -0700101 @returns An OFInput object
Rich Lanea06d0c32013-03-25 08:52:03 -0700102 """
103
104 # Parse the input file
105 try:
Rich Laned47e5a22013-05-09 14:21:16 -0700106 with open(filename, 'r') as f:
107 ast = parser.parse(f.read())
Rich Lanea06d0c32013-03-25 08:52:03 -0700108 except pyparsing.ParseBaseException as e:
109 print "Parse error in %s: %s" % (os.path.basename(filename), str(e))
110 sys.exit(1)
111
Rich Laned47e5a22013-05-09 14:21:16 -0700112 # Create the OFInput from the AST
113 try:
Andreas Wundsam76db0062013-11-15 13:34:41 -0800114 ofinput = frontend.create_ofinput(filename, ast)
Rich Laned47e5a22013-05-09 14:21:16 -0700115 except frontend.InputError as e:
116 print "Error in %s: %s" % (os.path.basename(filename), str(e))
Rich Lanea06d0c32013-03-25 08:52:03 -0700117 sys.exit(1)
118
119 return ofinput
120
Rich Lanea06d0c32013-03-25 08:52:03 -0700121def read_input():
122 """
123 Read in from files given on command line and update global state
124
125 @fixme Should select versions to support from command line
126 """
127
Andreas Wundsam76db0062013-11-15 13:34:41 -0800128 ofinputs_by_version = defaultdict(lambda: [])
Rich Lanea06d0c32013-03-25 08:52:03 -0700129 filenames = sorted(glob.glob("%s/openflow_input/*" % root_dir))
130
Rich Laned23c0132013-05-16 16:18:54 -0700131 # Ignore emacs backup files
132 filenames = [x for x in filenames if not x.endswith('~')]
133
Rich Lanea06d0c32013-03-25 08:52:03 -0700134 for filename in filenames:
135 log("Processing struct file: " + filename)
136 ofinput = process_input_file(filename)
137
Rich Lanea06d0c32013-03-25 08:52:03 -0700138 for wire_version in ofinput.wire_versions:
Rich Lanec9e111d2013-05-09 16:10:30 -0700139 ofinputs_by_version[wire_version].append(ofinput)
Andreas Wundsam76db0062013-11-15 13:34:41 -0800140 return ofinputs_by_version
Rich Lanea06d0c32013-03-25 08:52:03 -0700141
Andreas Wundsam76db0062013-11-15 13:34:41 -0800142def build_ir(ofinputs_by_version):
143 classes = []
144 enums = []
145 for wire_version, ofinputs in ofinputs_by_version.items():
146 version = OFVersions.from_wire(wire_version)
147 ofprotocol = loxi_ir.build_protocol(version, ofinputs)
148 loxi_globals.ir[version] = ofprotocol
Rich Lane4d9f0f62013-05-09 15:50:57 -0700149
Andreas Wundsam76db0062013-11-15 13:34:41 -0800150 loxi_globals.unified = loxi_ir.build_unified_ir(loxi_globals.ir)
Rich Lane38388e62013-04-08 14:09:46 -0700151
Andreas Wundsam76db0062013-11-15 13:34:41 -0800152################################################################
153#
154# Debug
155#
156################################################################
Rich Lanea06d0c32013-03-25 08:52:03 -0700157
158if __name__ == '__main__':
Andreas Wundsam76db0062013-11-15 13:34:41 -0800159 (options, args, target_versions) = cmdline.process_commandline()
Rich Lanea06d0c32013-03-25 08:52:03 -0700160 # @fixme Use command line params to select log
161
Andreas Wundsam76db0062013-11-15 13:34:41 -0800162 logging.basicConfig(level = logging.INFO if not options.verbose else logging.DEBUG)
163
164 # Import the language file
165 lang_file = "lang_%s" % options.lang
166 lang_module = __import__(lang_file)
167
168 if hasattr(lang_module, "config_sanity_check") and not lang_module.config_sanity_check():
Rich Lanea06d0c32013-03-25 08:52:03 -0700169 debug("Config sanity check failed\n")
170 sys.exit(1)
171
Rich Lanea06d0c32013-03-25 08:52:03 -0700172 # If list files, just list auto-gen files to stdout and exit
Andreas Wundsam76db0062013-11-15 13:34:41 -0800173 if options.list_files:
Rich Lanea06d0c32013-03-25 08:52:03 -0700174 for name in lang_module.targets:
Andreas Wundsam76db0062013-11-15 13:34:41 -0800175 print options.install_dir + '/' + name
Rich Lanea06d0c32013-03-25 08:52:03 -0700176 sys.exit(0)
177
Andreas Wundsam76db0062013-11-15 13:34:41 -0800178 log("\nGenerating files for target language %s\n" % options.lang)
Rich Lanea06d0c32013-03-25 08:52:03 -0700179
Andreas Wundsam76db0062013-11-15 13:34:41 -0800180 loxi_globals.OFVersions.target_versions = target_versions
181 inputs = read_input()
182 build_ir(inputs)
183 #log_all_class_info()
184 lang_module.generate(options.install_dir)