Skip to content

Commit

Permalink
tackle issue albertz#10 by adding a frontend for running main() from …
Browse files Browse the repository at this point in the history
…several c files
  • Loading branch information
markjenkins committed Aug 3, 2018
1 parent 6f405c2 commit 7b48236
Showing 1 changed file with 108 additions and 0 deletions.
108 changes: 108 additions & 0 deletions runcprog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/usr/bin/env python

"""Run a program written in C
Any arguments prior to the first "--" should be c source code files,
one of which must contain a main() declaration which can have void or
int as a return value and no paramaters or standard C main()
variable arguments (int argc0, char **argv0)
Any arguments after the first -- are passed to the C main
A current limitation is that this must be run from the same directory that
any local includes #include "example.h" are relative. Generally this is the
same directory as the c source file.
When calling a main accepting arguments, the first c file provided will
be the first (index 0) argument.
Example, if you have example1.c, example1.h, example2.c, and example2.h
you can ./runcprog.py example1.c example2.c -- arg1 arg2
as long as your current working directory is the same as example1.c and
example2.c
If you want to include some c preprocessor defines or macros, just make a
.h file and make that your first argument.
"""

# Copyright (c) 2018, Mark Jenkins <mark@markjenkins.ca> www.markjenkins.ca

# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

from sys import argv
from itertools import takewhile, dropwhile, chain, islice

import better_exchook
better_exchook.install()

from cparser import State, parse
from interpreter import Interpreter

def not_a_dashdash(x):
return x != "--"

def main():
c_code_files = list(takewhile(not_a_dashdash, argv[1:]))
if len(c_code_files) == 0:
raise Exception("You must provide at least one C source file")

state = State()
state.autoSetupSystemMacros()
state.autoSetupGlobalIncludeWrappers()
interpreter = Interpreter()
interpreter.register(state)

for cfile in c_code_files:
state = parse(cfile, state)

main_func = interpreter.getFunc("main")
if len(main_func.C_argTypes) == 0:
return_code = interpreter.runFunc("main", return_as_ctype=False)
else:
# if the main() function doesn't have zero arguments, it
# should have the standard two, (int argc0, char **argv0)
assert(len(main_func.C_argTypes) == 2)

# remove first "--" from arguments sequence and get everything after
# that if there's no "--" or nothing after it, this will be an empty
# sequence but chain() below will have no problem with that
arguments_to_c_prog_iter = islice(
dropwhile(not_a_dashdash, argv[1:]), 1, None)

# by chaining the program name (first c file) and possible remaining
# arguments we ensure there is at least one
arguments_to_c_prog = list(chain(
[c_code_files[0]], # first c file is first argument as programe name
arguments_to_c_prog_iter
) ) # chain, list

# return_as_ctype=False as we're expecting a simple int or None for void
return_code = interpreter.runFunc(
"main",
len(arguments_to_c_prog), arguments_to_c_prog,
return_as_ctype=False)

if isinstance(return_code, int):
exit(return_code)

if __name__ == "__main__":
main()

0 comments on commit 7b48236

Please sign in to comment.