| 1 | #! /usr/bin/python3
 | 
|---|
| 2 | 
 | 
|---|
| 3 | import fileinput
 | 
|---|
| 4 | import sys
 | 
|---|
| 5 | import re
 | 
|---|
| 6 | import os
 | 
|---|
| 7 | from enum import Enum
 | 
|---|
| 8 | 
 | 
|---|
| 9 | class Section(Enum):
 | 
|---|
| 10 |     PREAMBLE = 1
 | 
|---|
| 11 |     EXP_TYPE = 2
 | 
|---|
| 12 |     EXP_VALUE = 3
 | 
|---|
| 13 |     STATIC = 4
 | 
|---|
| 14 |     UNKNOWN = 5
 | 
|---|
| 15 | 
 | 
|---|
| 16 | class ValueSubsection(Enum):
 | 
|---|
| 17 |     FUNCTION = 1
 | 
|---|
| 18 |     VARIABLE = 2
 | 
|---|
| 19 |     NA = 3
 | 
|---|
| 20 | 
 | 
|---|
| 21 | outfile = sys.argv[1]
 | 
|---|
| 22 | outfile_local = os.path.basename(outfile)
 | 
|---|
| 23 | parts = re.match(r"(?P<module>.*)\.(?P<mode>[^\.]*)\.[hc]$", outfile_local)
 | 
|---|
| 24 | module = parts.group('module')
 | 
|---|
| 25 | outtype = parts.group('mode')
 | 
|---|
| 26 | 
 | 
|---|
| 27 | srcfile = os.path.join(os.path.dirname(outfile), module) + ".src.c"
 | 
|---|
| 28 | circImpVar = "__{mod}_{ty}_IMPORTING__".format(mod=module.upper(), ty=outtype.upper())
 | 
|---|
| 29 | 
 | 
|---|
| 30 | sys.stdout = open(outfile, 'w')
 | 
|---|
| 31 | 
 | 
|---|
| 32 | # data about the current //#-delimited chunk of file
 | 
|---|
| 33 | section = Section.PREAMBLE
 | 
|---|
| 34 | valueSubsection = ValueSubsection.NA
 | 
|---|
| 35 | lines = []
 | 
|---|
| 36 | 
 | 
|---|
| 37 | def declOnly():
 | 
|---|
| 38 |     if valueSubsection == ValueSubsection.VARIABLE:
 | 
|---|
| 39 |         eqpos = lines[0].find('=')
 | 
|---|
| 40 |         lines[0] = lines[0][0:eqpos]
 | 
|---|
| 41 |         print( 'extern', lines[0], ';' )
 | 
|---|
| 42 |     else:
 | 
|---|
| 43 |         if lines[0].endswith("{"):
 | 
|---|
| 44 |             lines[0] = lines[0][0:len(lines[0])-2].rstrip()
 | 
|---|
| 45 |         print( lines[0], ';' )
 | 
|---|
| 46 | 
 | 
|---|
| 47 | def fulldump():
 | 
|---|
| 48 |     for line in lines:
 | 
|---|
| 49 |         print(line)
 | 
|---|
| 50 | 
 | 
|---|
| 51 | def flush():
 | 
|---|
| 52 |     global lines
 | 
|---|
| 53 |     # print("\t// flush", outtype, section)
 | 
|---|
| 54 | 
 | 
|---|
| 55 |     if (section == Section.PREAMBLE):
 | 
|---|
| 56 |         postpreamble()
 | 
|---|
| 57 |     elif (len(lines) == 0):
 | 
|---|
| 58 |         return
 | 
|---|
| 59 |     elif (outtype == 'tdcl') & (section == Section.EXP_TYPE):
 | 
|---|
| 60 |         declOnly()
 | 
|---|
| 61 |     elif (outtype == 'defn') & (section == Section.EXP_TYPE):
 | 
|---|
| 62 |         fulldump()
 | 
|---|
| 63 |     elif (outtype == 'defn') & (section == Section.EXP_VALUE):
 | 
|---|
| 64 |         declOnly()
 | 
|---|
| 65 |     elif (outtype == 'impl') & (section == Section.EXP_VALUE):
 | 
|---|
| 66 |         fulldump()
 | 
|---|
| 67 |     elif (outtype == 'impl') & (section == Section.STATIC):
 | 
|---|
| 68 |         fulldump()
 | 
|---|
| 69 |     else:
 | 
|---|
| 70 |         for line in lines:
 | 
|---|
| 71 |             pass #print("//", line)
 | 
|---|
| 72 | 
 | 
|---|
| 73 |     lines = []
 | 
|---|
| 74 | 
 | 
|---|
| 75 | class ImportStyle(Enum):
 | 
|---|
| 76 |     NO_EXPORT = 1
 | 
|---|
| 77 |     EXPORT_INCOMPLETE = 2
 | 
|---|
| 78 |     EXPORT_COMPLETE = 3
 | 
|---|
| 79 | 
 | 
|---|
| 80 | def emitInclude(imodule, iftype):
 | 
|---|
| 81 |     print('#include "{mod}.{typ}.h"'.format(mod=imodule, typ=iftype))
 | 
|---|
| 82 | 
 | 
|---|
| 83 | def import_(cmd):
 | 
|---|
| 84 |     if section == Section.PREAMBLE:
 | 
|---|
| 85 |         if cmd.startswith("auto"):
 | 
|---|
| 86 |             cmd = cmd.replace("auto","").lstrip()
 | 
|---|
| 87 |             if cmd.startswith("&"):
 | 
|---|
| 88 |                 cmd = cmd.replace("&","").lstrip()
 | 
|---|
| 89 |                 style = ImportStyle.EXPORT_INCOMPLETE
 | 
|---|
| 90 |             else:
 | 
|---|
| 91 |                 style = ImportStyle.EXPORT_COMPLETE
 | 
|---|
| 92 |         elif cmd.startswith("static"):
 | 
|---|
| 93 |             cmd = cmd.replace("static","").lstrip()
 | 
|---|
| 94 |             style = ImportStyle.NO_EXPORT
 | 
|---|
| 95 |         else:
 | 
|---|
| 96 |             print("#error import not understood:", cmd)            
 | 
|---|
| 97 |             style = ImportStyle.NO_EXPORT
 | 
|---|
| 98 |         imodule = cmd
 | 
|---|
| 99 |         if( style != ImportStyle.EXPORT_COMPLETE) & (outtype == "impl"):
 | 
|---|
| 100 |             emitInclude(imodule, "defn")
 | 
|---|
| 101 |         if (style == ImportStyle.EXPORT_COMPLETE) & (outtype == "defn"):
 | 
|---|
| 102 |             emitInclude(imodule, "defn")
 | 
|---|
| 103 |         if (style != ImportStyle.NO_EXPORT) & (outtype == "tdcl"):
 | 
|---|
| 104 |             emitInclude(imodule, outtype)
 | 
|---|
| 105 |     else:
 | 
|---|
| 106 |         print("#error illegal place for: import ", cmd)
 | 
|---|
| 107 | 
 | 
|---|
| 108 | def beginunit():
 | 
|---|
| 109 |     print("//", outfile_local)
 | 
|---|
| 110 |     if (outtype == "tdcl"):
 | 
|---|
| 111 |         print("#pragma once")
 | 
|---|
| 112 |     elif outtype == "defn":
 | 
|---|
| 113 |         print("#ifdef", circImpVar)
 | 
|---|
| 114 |         print("#error Illegal circularity detected")
 | 
|---|
| 115 |         print("#else")
 | 
|---|
| 116 |         print("#define", circImpVar)
 | 
|---|
| 117 |     if outtype == "defn":
 | 
|---|
| 118 |         emitInclude(module, "tdcl")
 | 
|---|
| 119 |     elif outtype == "impl":
 | 
|---|
| 120 |         emitInclude(module, "defn")
 | 
|---|
| 121 | 
 | 
|---|
| 122 | def postpreamble():
 | 
|---|
| 123 |     if outtype == "defn":
 | 
|---|
| 124 |         print("#undef", circImpVar)
 | 
|---|
| 125 |         print("#pragma once")
 | 
|---|
| 126 | 
 | 
|---|
| 127 | 
 | 
|---|
| 128 | 
 | 
|---|
| 129 | def endunit():
 | 
|---|
| 130 |     if outtype == "defn":
 | 
|---|
| 131 |         print("#endif // ", circImpVar)
 | 
|---|
| 132 | 
 | 
|---|
| 133 | try:
 | 
|---|
| 134 |     with open(srcfile, "r") as file:
 | 
|---|
| 135 |         beginunit()
 | 
|---|
| 136 |         for line in file:
 | 
|---|
| 137 |             line = line.rstrip()
 | 
|---|
| 138 |             if ( line.startswith("#import") ):
 | 
|---|
| 139 |                 line = line.replace("#import", "").lstrip()
 | 
|---|
| 140 |                 import_(line)
 | 
|---|
| 141 |             elif ( line.startswith("//#") ):
 | 
|---|
| 142 |                 flush()
 | 
|---|
| 143 |                 line = line.replace("//#", "").lstrip()
 | 
|---|
| 144 |                 if line[0] == '@':
 | 
|---|
| 145 |                     section = Section.EXP_TYPE
 | 
|---|
| 146 |                     valueSubsection = ValueSubsection.NA
 | 
|---|
| 147 |                 elif line[0] == '$':
 | 
|---|
| 148 |                     section = Section.EXP_VALUE
 | 
|---|
| 149 |                     valueSubsection = ValueSubsection.NA
 | 
|---|
| 150 |                     # print("\t// object decl:{name}, with deps:{decldeps}".format(
 | 
|---|
| 151 |                     #     name=name, decldeps=decldeps))
 | 
|---|
| 152 |                     line = line[1:]
 | 
|---|
| 153 |                     if line[0] == 'f':
 | 
|---|
| 154 |                         valueSubsection = ValueSubsection.FUNCTION
 | 
|---|
| 155 |                     elif line[0] == 'v':
 | 
|---|
| 156 |                         valueSubsection = ValueSubsection.VARIABLE
 | 
|---|
| 157 |                     else:
 | 
|---|
| 158 |                         print("#error $-subdirective not understood: ", line)
 | 
|---|
| 159 |                         valueSubsection = ValueSubsection.NA
 | 
|---|
| 160 |                 elif line[0] == '-':
 | 
|---|
| 161 |                     section = Section.STATIC
 | 
|---|
| 162 |                     valueSubsection = ValueSubsection.NA
 | 
|---|
| 163 |                 else:
 | 
|---|
| 164 |                     print("#error directive not understood:", line)
 | 
|---|
| 165 |                     section = Section.UNKNOWN
 | 
|---|
| 166 |                     valueSubsection = ValueSubsection.NA
 | 
|---|
| 167 |                 line = line[1:]
 | 
|---|
| 168 |             else:
 | 
|---|
| 169 |                 line = line.split("//")[0].rstrip()
 | 
|---|
| 170 |                 if (line):
 | 
|---|
| 171 |                     lines.append(line)
 | 
|---|
| 172 |         flush()
 | 
|---|
| 173 |         endunit()
 | 
|---|
| 174 | except FileNotFoundError:
 | 
|---|
| 175 |     print("Error: The file '" + srcfile + "' was not found.")
 | 
|---|
| 176 | 
 | 
|---|
| 177 | 
 | 
|---|