Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1import io 

2import keyword 

3 

4from ply import lex 

5from ply import yacc 

6 

7from logging import getLogger, basicConfig, DEBUG, INFO 

8 

9log = getLogger(__name__) 

10 

11reserved = """ 

12CONST ENUM STRUCT OPAQUE UNSIGNED STRING TYPEDEF CASE DEFAULT VOID 

13UNION SWITCH BOOL HYPER LONG INT NETOBJ TRUE FALSE 

14PROGRAM VERSION 

15""".strip().split() 

16 

17tokens = reserved + """ 

18ID TYPEID ICONST 

19EQ LT GT MINUS PLUS TIMES 

20SEMI COLON COMMA 

21LPAREN RPAREN 

22LBRACKET RBRACKET 

23LBRACE RBRACE 

24""".strip().split() 

25 

26t_ignore = " \t\x0c" 

27 

28ngname = keyword.kwlist + dir(__builtins__) 

29 

30 

31def t_NEWLINE(t): 

32 r'\n+' 

33 

34 

35t_TIMES = r'\*' 

36t_MINUS = r'\-' 

37t_PLUS = r'\+' 

38t_LT = r'<' 

39t_GT = r'>' 

40t_EQ = r'=' 

41t_LPAREN = r'\(' 

42t_RPAREN = r'\)' 

43t_LBRACKET = r'\[' 

44t_RBRACKET = r'\]' 

45t_LBRACE = r'\{' 

46t_RBRACE = r'\}' 

47t_COMMA = r',' 

48t_SEMI = r';' 

49t_COLON = r':' 

50t_ICONST = r'[-+]?(0x?)?\d+' 

51t_ignore_COMMENT = r'(/\*(.|\n)*?\*/|//[^\n]*\n$)' 

52t_ignore_PP = r'\#(.)*?\n' 

53t_ignore_PX = r'\%(.)*?\n' 

54 

55reserved_map = { 

56 "TRUE": "ICONST", 

57 "FALSE": "ICONST", 

58} 

59for r in reserved: 

60 reserved_map[r.lower()] = r 

61 

62constmap = {} 

63 

64 

65def t_error(t): 

66 log.error("error: %s", t) 

67 

68 

69def t_ID(t): 

70 r'[A-Za-z_][\w_]*' 

71 t.type = reserved_map.get(t.value, "ID") 

72 while t.value in ngname: 

73 t.value = t.value + "_" 

74 return t 

75 

76 

77def sequence(t, first, second): 

78 if len(t) == first + 1: 

79 t[0] = [t[first]] 

80 elif len(t) == second + 1: 

81 if t[0] is None: 

82 t[0] = [t[first]] 

83 if t[second] is not None: 

84 t[0].extend(t[second]) 

85 else: 

86 t[0].append(t[first]) 

87 

88 

89def valmap(s): 

90 return dict(s) 

91 

92 

93def p_statements_1(t): 

94 """statements : statement statements 

95 | statement""" 

96 log.debug("p_statements_1: %s", t) 

97 sequence(t, 1, 2) 

98 

99 

100def p_statement(t): 

101 """statement : defconst SEMI 

102 | defenum SEMI 

103 | defstruct SEMI 

104 | typedef SEMI 

105 | union SEMI 

106 | program SEMI""" 

107 log.debug("p_statement_1: %s", t) 

108 t[0] = t[1] 

109 

110 

111def p_defconst(t): 

112 """defconst : CONST ID EQ ICONST""" 

113 log.debug("defconst: %s %s", t[2], t[4]) 

114 reserved_map[t[2]] = "ICONST" 

115 constmap[t[2]] = t[4] 

116 t[0] = {"const": t[2], "value": t[4]} 

117 

118 

119def p_defenum(t): 

120 """defenum : ENUM ID LBRACE enuments RBRACE""" 

121 log.debug("p_defenum: %s %s", t[2], t[4]) 

122 reserved_map[t[2]] = "TYPEID" 

123 t[0] = {"enum": t[2], "values": valmap(t[4])} 

124 

125 

126def p_enuments(t): 

127 """enuments : enument 

128 | enument COMMA enuments""" 

129 log.debug("p_enuments_1: %s", list(t)) 

130 sequence(t, 1, 3) 

131 

132 

133def p_enument(t): 

134 """enument : ID EQ ICONST""" 

135 log.debug("p_enuments_2: %s %s", t[1], t[3]) 

136 reserved_map[t[1]] = "ICONST" 

137 t[0] = (t[1], t[3]) 

138 

139 

140def p_struct(t): 

141 """defstruct : STRUCT ID LBRACE structents RBRACE 

142 | STRUCT TYPEID LBRACE structents RBRACE""" 

143 log.debug("p_struct: %s", t[2]) 

144 reserved_map[t[2]] = "TYPEID" 

145 t[0] = {"struct": t[2], "entries": t[4]} 

146 

147 

148def p_structents(t): 

149 """structents : structent structents 

150 | structent""" 

151 log.debug("p_structents: %s", list(t)) 

152 sequence(t, 1, 2) 

153 

154 

155def p_structent_1(t): 

156 """structent : typeid ID SEMI 

157 | typeid TYPEID SEMI 

158 | ID ID SEMI""" 

159 log.debug("p_structent_1: %s %s", t[1], t[2]) 

160 t[0] = {"name": t[2], "type": t[1], "note": "raw"} 

161 

162 

163def p_structent_2(t): 

164 """structent : typeid ID LT ICONST GT SEMI 

165 | typeid ID LT GT SEMI 

166 | typeid ID LBRACKET ICONST RBRACKET SEMI 

167 | typeid ID LBRACKET RBRACKET SEMI""" 

168 log.debug("p_structent_2: %s", list(t)) 

169 t[0] = {"name": t[2], "type": t[1], "note": "array"} 

170 if len(t) == 7: 

171 t[0]["length"] = t[4] 

172 if t[3] == "[": 

173 t[0]["fixed"] = True 

174 

175 

176def p_structent_3(t): 

177 """structent : ID TIMES ID SEMI 

178 | typeid TIMES ID SEMI""" 

179 log.debug("p_structent_3: %s", list(t)) 

180 t[0] = {"name": t[3], "type": t[1], "note": "pointer"} 

181 

182 

183def p_typeid(t): 

184 """typeid : TYPEID 

185 | OPAQUE 

186 | UNSIGNED 

187 | UNSIGNED HYPER 

188 | UNSIGNED INT 

189 | UNSIGNED LONG 

190 | STRING 

191 | NETOBJ 

192 | BOOL 

193 | HYPER 

194 | LONG 

195 | INT 

196 | VOID 

197 | STRUCT TYPEID""" 

198 log.debug("p_typeid: %s", t[1]) 

199 t[0] = t[1] 

200 

201 

202def p_typedef_1(t): 

203 """typedef : TYPEDEF typeid ID 

204 | TYPEDEF typeid TYPEID 

205 | TYPEDEF typeid ID LT ICONST GT 

206 | TYPEDEF typeid ID LT GT 

207 | TYPEDEF typeid ID LBRACKET ICONST RBRACKET""" 

208 log.debug("p_typedef: %s", t[3]) 

209 reserved_map[t[3]] = "TYPEID" 

210 t[0] = {"typedef": t[3], "type": t[2]} 

211 if len(t) == 4: 

212 t[0]["note"] = "raw" 

213 else: 

214 t[0]["note"] = "array" 

215 if len(t) == 7: 

216 t[0]["length"] = t[5] 

217 if len(t) > 5 and t[4] == "[": 

218 t[0]["fixed"] = True 

219 

220 

221def p_typedef_2(t): 

222 """typedef : TYPEDEF STRUCT ID TIMES ID""" 

223 log.debug("p_typedef_2: %s %s", t[3], t[5]) 

224 reserved_map[t[5]] = "TYPEID" 

225 t[0] = {"typedef": t[3], "type": t[5], "note": "pointer"} 

226 

227 

228def p_union(t): 

229 """union : UNION ID SWITCH LPAREN typeid ID RPAREN LBRACE cases RBRACE""" 

230 log.debug("p_union: %s %s", t[2], t[5]) 

231 reserved_map[t[2]] = "TYPEID" 

232 t[0] = {"union": t[2], "cond": {"type": t[5], "name": t[6]}, "cases": t[9]} 

233 

234 

235def p_cases(t): 

236 """cases : case cases 

237 | case""" 

238 log.debug("p_cases: %s", list(t)) 

239 sequence(t, 1, 2) 

240 

241 

242def p_case(t): 

243 """case : caselabel typeid SEMI 

244 | caselabel 

245 | caselabel ID SEMI 

246 | caselabel ID ID SEMI 

247 | caselabel typeid ID SEMI""" 

248 log.debug("p_case: %s", t[1]) 

249 t[0] = {"label": t[1]} 

250 if len(t) != 2: 

251 t[0]["type"] = t[2] 

252 if len(t) == 5: 

253 t[0]["name"] = t[3] 

254 

255 

256def p_caselabel_1(t): 

257 """caselabel : CASE ICONST COLON""" 

258 log.debug("p_caselabel: %s", t[2]) 

259 t[0] = t[2] 

260 

261 

262def p_caselabel_2(t): 

263 """caselabel : DEFAULT COLON""" 

264 log.debug("p_caselabel: %s", t[1]) 

265 t[0] = t[1] 

266 

267 

268def p_program(t): 

269 """program : PROGRAM ID LBRACE versions RBRACE EQ ICONST""" 

270 log.debug("p_program: %s %s %s", t[2], t[4], t[7]) 

271 t[0] = {"program": t[2], "num": t[7], "versions": t[4]} 

272 

273 

274def p_versions(t): 

275 """versions : version versions 

276 | version""" 

277 log.debug("p_versions: %s", list(t)) 

278 sequence(t, 1, 2) 

279 

280 

281def p_version(t): 

282 """version : VERSION ID LBRACE procs RBRACE EQ ICONST SEMI""" 

283 log.debug("p_version: %s id=%s procs=%s", t[2], t[7], t[4]) 

284 t[0] = {"version": t[2], "num": t[7], "procs": t[4]} 

285 

286 

287def p_procs(t): 

288 """procs : proc procs 

289 | proc""" 

290 log.debug("p_procs: %s", list(t)) 

291 sequence(t, 1, 2) 

292 

293 

294def p_proc(t): 

295 """proc : typeid ID LPAREN typeid RPAREN EQ ICONST SEMI""" 

296 log.debug("p_proc: %s id=%s arg=%s res=%s", t[2], t[7], t[4], t[1]) 

297 t[0] = {"id": t[7], "name": t[2], "arg": t[4], "res": t[1]} 

298 

299 

300def p_error(t): 

301 log.error("error: %s", t) 

302 

303 

304def parse_file(fp, debug=False, defines={}): 

305 log.debug("defines: %s", defines) 

306 for k, v in defines.items(): 

307 log.info("const: %s=%s", k, v) 

308 constmap[k] = str(v) 

309 if isinstance(v, int): 

310 reserved_map[k] = "ICONST" 

311 log.debug("reserved: %s=%s", k, v) 

312 lexer = lex.lex() 

313 parser = yacc.yacc(debug=debug) 

314 if not hasattr(fp, "encoding"): 

315 fp = io.TextIOWrapper(fp) 

316 return yacc.parse(fp.read(), debug=debug) 

317 

318 

319def get_lexer(fp): 

320 lx = lex.lex() 

321 lx.input(fp.read()) 

322 return lx 

323 

324 

325if __name__ == "__main__": 

326 import sys 

327 import yaml 

328 basicConfig(level=DEBUG) 

329 mode = "lex" 

330 defs = {"LM_MAXSTRLEN": 1024, "MAXNAMELEN": 1025, "MAXNETNAMELEN": 255} 

331 # defs = {} 

332 if len(sys.argv) >= 2: 

333 mode = sys.argv[1] 

334 if mode == "lex": 

335 for token in get_lexer(sys.stdin): 

336 log.info("token %s", token) 

337 elif mode == "yacc": 

338 result = parse_file(sys.stdin, debug=True, defines=defs) 

339 log.debug("parsed %s", result) 

340 log.info("const %s", constmap) 

341 sys.stdout.write(yaml.dump(result)) 

342 elif mode == "yacc_cpp": 

343 import subprocess 

344 with subprocess.Popen(["cpp"], stdin=subprocess.PIPE, 

345 stdout=subprocess.PIPE) as p: 

346 p.stdin.write(sys.stdin.read().encode('utf-8')) 

347 p.stdin.close() 

348 result = parse_file(p.stdout, debug=False, defines=defs) 

349 log.debug("parsed %s", result) 

350 log.info("const %s", constmap) 

351 sys.stdout.write(yaml.dump(result))