blob: 5ef4d59d39269e13ef0143b8a08d937e45a921cb [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:
Rich Lane72875d62013-11-13 12:39:53 -0800114 ofinput = frontend.create_ofinput(os.path.basename(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 Laned7987552013-11-13 10:38:54 -0800134 # Read input files
Rich Lanea06d0c32013-03-25 08:52:03 -0700135 for filename in filenames:
136 log("Processing struct file: " + filename)
137 ofinput = process_input_file(filename)
138
Rich Lanea06d0c32013-03-25 08:52:03 -0700139 for wire_version in ofinput.wire_versions:
Murat Parlakisikf95672c2016-12-05 00:53:17 -0800140 version = loxi_globals.OFVersions.from_wire(wire_version)
141 if version in loxi_globals.OFVersions.target_versions:
142 ofinputs_by_version[wire_version].append(ofinput)
Andreas Wundsam76db0062013-11-15 13:34:41 -0800143 return ofinputs_by_version
Rich Lanea06d0c32013-03-25 08:52:03 -0700144
Andreas Wundsam76db0062013-11-15 13:34:41 -0800145def build_ir(ofinputs_by_version):
146 classes = []
147 enums = []
148 for wire_version, ofinputs in ofinputs_by_version.items():
149 version = OFVersions.from_wire(wire_version)
150 ofprotocol = loxi_ir.build_protocol(version, ofinputs)
151 loxi_globals.ir[version] = ofprotocol
Rich Lane4d9f0f62013-05-09 15:50:57 -0700152
Andreas Wundsam76db0062013-11-15 13:34:41 -0800153 loxi_globals.unified = loxi_ir.build_unified_ir(loxi_globals.ir)
Rich Lane38388e62013-04-08 14:09:46 -0700154
Andreas Wundsam76db0062013-11-15 13:34:41 -0800155################################################################
156#
157# Debug
158#
159################################################################
Rich Lanea06d0c32013-03-25 08:52:03 -0700160
161if __name__ == '__main__':
Andreas Wundsam76db0062013-11-15 13:34:41 -0800162 (options, args, target_versions) = cmdline.process_commandline()
Rich Lanea06d0c32013-03-25 08:52:03 -0700163 # @fixme Use command line params to select log
164
Andreas Wundsam76db0062013-11-15 13:34:41 -0800165 logging.basicConfig(level = logging.INFO if not options.verbose else logging.DEBUG)
166
167 # Import the language file
168 lang_file = "lang_%s" % options.lang
169 lang_module = __import__(lang_file)
170
Andreas Wundsam76db0062013-11-15 13:34:41 -0800171 log("\nGenerating files for target language %s\n" % options.lang)
Rich Lanea06d0c32013-03-25 08:52:03 -0700172
Andreas Wundsam76db0062013-11-15 13:34:41 -0800173 loxi_globals.OFVersions.target_versions = target_versions
174 inputs = read_input()
175 build_ir(inputs)
Andreas Wundsam76db0062013-11-15 13:34:41 -0800176 lang_module.generate(options.install_dir)