From a0388bada4016bc0c3be6154c159faf80ce18d01 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Fri, 8 May 2020 20:44:25 +0900 Subject: [PATCH] Add -o and --help options --- Makefile | 1 + chibicc.h | 2 +- codegen.c | 9 ++++++--- main.c | 55 +++++++++++++++++++++++++++++++++++++++++++++----- test-driver.sh | 25 +++++++++++++++++++++++ test.sh | 2 +- 6 files changed, 84 insertions(+), 10 deletions(-) create mode 100755 test-driver.sh diff --git a/Makefile b/Makefile index b733d58..2b60351 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ $(OBJS): chibicc.h test: chibicc ./test.sh + ./test-driver.sh clean: rm -f chibicc *.o *~ tmp* diff --git a/chibicc.h b/chibicc.h index 0aed332..d57bf3b 100644 --- a/chibicc.h +++ b/chibicc.h @@ -186,4 +186,4 @@ void add_type(Node *node); // codegen.c // -void codegen(Obj *prog); +void codegen(Obj *prog, FILE *out); diff --git a/codegen.c b/codegen.c index fea1d3b..c2c3ed3 100644 --- a/codegen.c +++ b/codegen.c @@ -1,5 +1,6 @@ #include "chibicc.h" +static FILE *output_file; static int depth; static char *argreg8[] = {"%dil", "%sil", "%dl", "%cl", "%r8b", "%r9b"}; static char *argreg64[] = {"%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9"}; @@ -11,9 +12,9 @@ static void gen_stmt(Node *node); static void println(char *fmt, ...) { va_list ap; va_start(ap, fmt); - vprintf(fmt, ap); + vfprintf(output_file, fmt, ap); va_end(ap); - printf("\n"); + fprintf(output_file, "\n"); } static int count(void) { @@ -292,7 +293,9 @@ static void emit_text(Obj *prog) { } } -void codegen(Obj *prog) { +void codegen(Obj *prog, FILE *out) { + output_file = out; + assign_lvar_offsets(prog); emit_data(prog); emit_text(prog); diff --git a/main.c b/main.c index 42ae748..a8f95ab 100644 --- a/main.c +++ b/main.c @@ -1,15 +1,60 @@ #include "chibicc.h" +static char *opt_o; + +static char *input_path; + +static void usage(int status) { + fprintf(stderr, "chibicc [ -o ] \n"); + exit(status); +} + +static void parse_args(int argc, char **argv) { + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--help")) + usage(0); + + if (!strcmp(argv[i], "-o")) { + if (!argv[++i]) + usage(1); + opt_o = argv[i]; + continue; + } + + if (!strncmp(argv[i], "-o", 2)) { + opt_o = argv[i] + 2; + continue; + } + + if (argv[i][0] == '-' && argv[i][1] != '\0') + error("unknown argument: %s", argv[i]); + + input_path = argv[i]; + } + + if (!input_path) + error("no input files"); +} + +static FILE *open_file(char *path) { + if (!path || strcmp(path, "-") == 0) + return stdout; + + FILE *out = fopen(path, "w"); + if (!out) + error("cannot open output file: %s: %s", path, strerror(errno)); + return out; +} + int main(int argc, char **argv) { - if (argc != 2) - error("%s: invalid number of arguments", argv[0]); + parse_args(argc, argv); // Tokenize and parse. - Token *tok = tokenize_file(argv[1]); + Token *tok = tokenize_file(input_path); Obj *prog = parse(tok); // Traverse the AST to emit assembly. - codegen(prog); - + FILE *out = open_file(opt_o); + codegen(prog, out); return 0; } diff --git a/test-driver.sh b/test-driver.sh new file mode 100755 index 0000000..113336a --- /dev/null +++ b/test-driver.sh @@ -0,0 +1,25 @@ +#!/bin/sh +tmp=`mktemp -d /tmp/chibicc-test-XXXXXX` +trap 'rm -rf $tmp' INT TERM HUP EXIT +echo > $tmp/empty.c + +check() { + if [ $? -eq 0 ]; then + echo "testing $1 ... passed" + else + echo "testing $1 ... failed" + exit 1 + fi +} + +# -o +rm -f $tmp/out +./chibicc -o $tmp/out $tmp/empty.c +[ -f $tmp/out ] +check -o + +# --help +./chibicc --help 2>&1 | grep -q chibicc +check --help + +echo OK diff --git a/test.sh b/test.sh index 3c65703..0eda6e0 100755 --- a/test.sh +++ b/test.sh @@ -14,7 +14,7 @@ assert() { expected="$1" input="$2" - echo "$input" | ./chibicc - > tmp.s || exit + echo "$input" | ./chibicc -o tmp.s - || exit gcc -static -o tmp tmp.s tmp2.o ./tmp actual="$?"