Skip to content

Commit 8cb2bad

Browse files
committed
PIR: add parse command to pirinspector
1 parent 03751ba commit 8cb2bad

File tree

5 files changed

+129
-8
lines changed

5 files changed

+129
-8
lines changed

chb/app/CHVersion.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
chbversion: str = "0.3.0-20250308"
1+
chbversion: str = "0.3.0-20250309"

chb/ast/astutil.py

Lines changed: 96 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,22 @@
3131
import subprocess
3232
import sys
3333

34+
import xml.etree.ElementTree as ET
35+
3436
from typing import Any, Dict, List, NoReturn, Optional
3537

3638
from chb.ast.AbstractSyntaxTree import AbstractSyntaxTree
39+
from chb.ast.ASTCPrettyPrinter import ASTCPrettyPrinter
3740
from chb.ast.ASTDeserializer import ASTDeserializer
3841
import chb.ast.ASTNode as AST
3942
from chb.ast.ASTViewer import ASTViewer
4043
import chb.ast.astdotutil as DU
4144

45+
from chb.astparser.ASTCParseManager import ASTCParseManager
46+
4247

4348
def print_pirinfo(pirjson: Dict[str, Any]) -> None:
44-
print("PIR-version: " + pirjson["pir-version"])
49+
print("PIR-version: " + pirjson["pir-version"])
4550
if "created-by" in pirjson:
4651
cb = pirjson["created-by"]
4752
print(
@@ -146,7 +151,7 @@ def get_function_addr(pirjson: Dict[str, Any], function: Optional[str]) -> str:
146151
+ "\n".join(
147152
(" " + va.ljust(8) + name) for (va, name) in functions.items()))
148153
exit(1)
149-
154+
150155

151156
def view_ast_function(
152157
faddr: str,
@@ -166,7 +171,7 @@ def view_ast_function(
166171
else:
167172
g = viewer.to_graph(dfn.high_unreduced_ast)
168173
return g
169-
174+
170175

171176
def viewastcmd(args: argparse.Namespace) -> NoReturn:
172177

@@ -178,7 +183,7 @@ def viewastcmd(args: argparse.Namespace) -> NoReturn:
178183
cutoff: Optional[str] = args.cutoff
179184

180185
with open(pirfile, "r") as fp:
181-
pirjson = json.load(fp)
186+
pirjson = json.load(fp)
182187

183188
faddr = get_function_addr(pirjson, function)
184189
g = view_ast_function(faddr, level, pirjson, cutoff)
@@ -196,7 +201,7 @@ def viewinstrcmd(args: argparse.Namespace) -> NoReturn:
196201
outputfilename: str = args.output
197202

198203
with open(pirfile, "r") as fp:
199-
pirjson = json.load(fp)
204+
pirjson = json.load(fp)
200205

201206
faddr = get_function_addr(pirjson, function)
202207
deserializer = ASTDeserializer(pirjson)
@@ -231,7 +236,7 @@ def viewexprcmd(args: argparse.Namespace) -> NoReturn:
231236
outputfilename: str = args.output
232237

233238
with open(pirfile, "r") as fp:
234-
pirjson = json.load(fp)
239+
pirjson = json.load(fp)
235240

236241
faddr = get_function_addr(pirjson, function)
237242
deserializer = ASTDeserializer(pirjson)
@@ -294,3 +299,88 @@ def include_loc(loc: str) -> bool:
294299
+ str(exprec[1])
295300
+ ")")
296301
exit(0)
302+
303+
304+
def printsrccmd(args: argparse.Namespace) -> NoReturn:
305+
306+
# arguments
307+
pirfile: str = args.pirfile
308+
function: str = args.function
309+
310+
with open(pirfile, "r") as fp:
311+
pirjson = json.load(fp)
312+
313+
faddr = get_function_addr(pirjson, function)
314+
deserializer = ASTDeserializer(pirjson)
315+
(symtable, astnode) = deserializer.lifted_functions[faddr]
316+
pp = ASTCPrettyPrinter(symtable, annotations=deserializer.annotations)
317+
print(pp.to_c(astnode, include_globals=True))
318+
319+
exit(0)
320+
321+
322+
def parsecmd(args: argparse.Namespace) -> NoReturn:
323+
324+
# arguments
325+
pirfile: str = args.pirfile
326+
cname: str = args.cname
327+
328+
if not ASTCParseManager().check_cparser():
329+
print("*" * 80)
330+
print("CodeHawk CIL parser not found.")
331+
print("~" * 80)
332+
print("Copy CHC/cchcil/parseFile from the (compiled) codehawk ")
333+
print("repository to the chb/bin/binaries/linux directory in this ")
334+
print("repository, or ")
335+
print("set up ConfigLocal.py with another location for parseFile")
336+
print("*" * 80)
337+
exit(1)
338+
339+
cfilename = cname + ".c"
340+
with open(pirfile, "r") as fp:
341+
pirjson = json.load(fp)
342+
343+
lines: List[str] = []
344+
functions: Dict[str, AST.ASTStmt] = {}
345+
deserializer = ASTDeserializer(pirjson)
346+
printglobals = True
347+
for (faddr, (symtable, dfn)) in deserializer.lifted_functions.items():
348+
pp = ASTCPrettyPrinter(symtable, annotations=deserializer.annotations)
349+
lines.append(pp.to_c(dfn, include_globals=printglobals))
350+
functions[faddr] = dfn
351+
printglobals = False
352+
353+
with open(cfilename, "w") as fp:
354+
fp.write("\n".join(lines))
355+
356+
parsemanager = ASTCParseManager()
357+
ifile = parsemanager.preprocess_file_with_gcc(cfilename)
358+
parsemanager.parse_ifile(ifile)
359+
360+
for (faddr, dfn) in functions.items():
361+
fname = faddr.replace("0x", "sub_")
362+
xpath = os.path.join(cname, "functions")
363+
xpath = os.path.join(xpath, fname)
364+
xfile = os.path.join(xpath, cname + "_" + fname + "_cfun.xml")
365+
366+
if os.path.isfile(xfile):
367+
try:
368+
tree = ET.parse(xfile)
369+
root = tree.getroot()
370+
rootnode = root.find("function")
371+
except ET.ParseError as e:
372+
raise Exception("Error in parsing " + xfile + ": "
373+
+ str(e.code) + ", " + str(e.position))
374+
else:
375+
print("Error: file " + xfile + " not found")
376+
exit(1)
377+
378+
if rootnode is None:
379+
print("Error: No function node found for " + fname)
380+
exit(1)
381+
382+
xsbody = rootnode.find("sbody")
383+
384+
385+
386+
exit(0)

chb/ast/pirinspector

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# ------------------------------------------------------------------------------
66
# The MIT License (MIT)
77
#
8-
# Copyright (c) 2023 Aarno Labs, LLC
8+
# Copyright (c) 2023-2025 Aarno Labs, LLC
99
#
1010
# Permission is hereby granted, free of charge, to any person obtaining a copy
1111
# of this software and associated documentation files (the "Software"), to deal
@@ -156,6 +156,26 @@ def parse() -> argparse.Namespace:
156156
)
157157
showaexprs.set_defaults(func=AU.showaexprscmd)
158158

159+
# ---------------------------------------------------------------- print ---
160+
printcmd = subparsers.add_parser("print")
161+
printparsers = printcmd.add_subparsers(title="show options")
162+
163+
# --- print sourcecode
164+
printsrc = printparsers.add_parser("src")
165+
printsrc.add_argument(
166+
"pirfile", help="name of json file with ast information")
167+
printsrc.add_argument(
168+
"function", help="name or address of funnction to print")
169+
printsrc.set_defaults(func=AU.printsrccmd)
170+
171+
# ---------------------------------------------------------------- parse ---
172+
parsecmd = subparsers.add_parser("parse")
173+
parsecmd.add_argument(
174+
"pirfile", help="name of json file with ast information")
175+
parsecmd.add_argument(
176+
"cname", help="name of c file to be created (without extension)")
177+
parsecmd.set_defaults(func=AU.parsecmd)
178+
159179
# -- parse
160180
args = parser.parse_args()
161181
return args

chb/cmdline/commandutil.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,16 @@ def analyzecmd(args: argparse.Namespace) -> NoReturn:
425425
logfilename: Optional[str] = args.logfilename
426426
logfilemode: str = args.logfilemode
427427

428+
if not os.path.isfile(Config().chx86_analyze):
429+
print_error(
430+
"CodeHawk analyzer executable not found.\n"
431+
+ ("~" * 80) + "\n"
432+
+ "Copy CHB/bchcmdline/chx86_analyze from the (compiled) "
433+
+ "codehawk repository to the\nchb/bin/binaries/linux directory "
434+
+ "in this directory, or\n"
435+
+ "set up ConfigLocal.py with another location for chx86_analyze")
436+
exit(1)
437+
428438
try:
429439
(path, xfile) = get_path_filename(xname)
430440
except UF.CHBError as e:

chb/util/Config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ def __init__(self) -> None:
6565
if self.platform == 'linux':
6666
self.linuxdir = os.path.join(self.binariesdir, "linux")
6767
self.chx86_analyze = os.path.join(self.linuxdir, "chx86_analyze")
68+
self.cparser = os.path.join(self.linuxdir, "parseFile")
6869

6970
elif self.platform == "macOS":
7071
self.macOSdir = os.path.join(self.binariesdir, "macOS")

0 commit comments

Comments
 (0)