diff --git a/Compiler/.idea/.idea.Compiler/.idea/workspace.xml b/Compiler/.idea/.idea.Compiler/.idea/workspace.xml index 4371fd7..a539953 100644 --- a/Compiler/.idea/.idea.Compiler/.idea/workspace.xml +++ b/Compiler/.idea/.idea.Compiler/.idea/workspace.xml @@ -20,14 +20,33 @@ - - + + + + + + + + + + + + + - - - - + + + + + + + + + + + + @@ -202,22 +221,22 @@ - + - - + + - - + + - - + + - + @@ -282,10 +301,10 @@ - - + + - + diff --git a/Compiler/Compiler.cs b/Compiler/Compiler.cs index d24c561..2dbe8b3 100644 --- a/Compiler/Compiler.cs +++ b/Compiler/Compiler.cs @@ -13,19 +13,35 @@ namespace Compiler { public static void Main(string[] args) { - if (args.Length != 1) + if (args.Length < 1) { - Console.WriteLine("Usage: Compiler "); + Console.WriteLine("Usage: Compiler [optional: -v]"); } else { + bool debug = false; + string inputFileName = args[0].Split("/").Last(); string outputPath = args[0].Substring(0, args[0].LastIndexOf("/")); - Compile(args[0], $"{outputPath}/assembly.s"); - Console.WriteLine($"Compiled to {outputPath}/assembly.s"); + if (args.Length == 2) + { + if (args[2] == "-v") + { + debug = true; + } + } + + Compile(args[0], $"{outputPath}/assembly.s", debug); + if (debug) + { + Console.WriteLine($"Compiled to {outputPath}/assembly.s"); + } ProcessStartInfo startInfo = new ProcessStartInfo() - {FileName = "gcc", Arguments = $"{outputPath}/assembly.s -o {outputPath}/program"}; + { + FileName = "gcc", + Arguments = $"{outputPath}/assembly.s -o {outputPath}/{inputFileName.Replace(".c", "")}" + }; Process proc = new Process() {StartInfo = startInfo,}; proc.Start(); @@ -33,14 +49,19 @@ namespace Compiler { Thread.Sleep(1); } - Console.WriteLine($"Assembled to {outputPath}/program"); + File.Delete($"{outputPath}/assembly.s"); - Console.WriteLine("Deleted assembly.s file. Done!"); + + if (debug) + { + Console.WriteLine($"Assembled to {outputPath}/program"); + Console.WriteLine("Deleted assembly.s file. Done!"); + } } } - static void Compile(string inputPath, string outputPath) + static void Compile(string inputPath, string outputPath, bool debug) { //Lexing Lexer.Lexer lexer = new Lexer.Lexer(); @@ -50,7 +71,10 @@ namespace Compiler string contents = file.ReadToEnd(); List tokens = lexer.Lex(contents); - Console.WriteLine($"Lexed {inputPath.Split("/").Last()}."); + if (debug) + { + Console.WriteLine($"Lexed {inputPath.Split("/").Last()}."); + } //Parsing Parser.Parser p = new Parser.Parser(tokens); @@ -58,7 +82,10 @@ namespace Compiler try { Node programNode = p.Parse(NodeType.ProgramNode); - Console.WriteLine($"Parsed \"{inputPath.Split("/").Last()}\""); + if (debug) + { + Console.WriteLine($"Parsed \"{inputPath.Split("/").Last()}\""); + } //Generating Generator.Generator generator = new Generator.Generator(); diff --git a/tests/week_1/invalid/missing_paren.c b/stage_1/invalid/missing_paren.c similarity index 100% rename from tests/week_1/invalid/missing_paren.c rename to stage_1/invalid/missing_paren.c diff --git a/tests/week_1/invalid/missing_retval.c b/stage_1/invalid/missing_retval.c similarity index 100% rename from tests/week_1/invalid/missing_retval.c rename to stage_1/invalid/missing_retval.c diff --git a/tests/week_1/invalid/no_brace.c b/stage_1/invalid/no_brace.c similarity index 100% rename from tests/week_1/invalid/no_brace.c rename to stage_1/invalid/no_brace.c diff --git a/tests/week_1/invalid/no_semicolon.c b/stage_1/invalid/no_semicolon.c similarity index 100% rename from tests/week_1/invalid/no_semicolon.c rename to stage_1/invalid/no_semicolon.c diff --git a/tests/week_1/invalid/no_space.c b/stage_1/invalid/no_space.c similarity index 100% rename from tests/week_1/invalid/no_space.c rename to stage_1/invalid/no_space.c diff --git a/tests/week_1/invalid/wrong_case.c b/stage_1/invalid/wrong_case.c similarity index 100% rename from tests/week_1/invalid/wrong_case.c rename to stage_1/invalid/wrong_case.c diff --git a/tests/week_1/valid/multi_digit.c b/stage_1/valid/multi_digit.c similarity index 100% rename from tests/week_1/valid/multi_digit.c rename to stage_1/valid/multi_digit.c diff --git a/tests/week_1/valid/newlines.c b/stage_1/valid/newlines.c similarity index 100% rename from tests/week_1/valid/newlines.c rename to stage_1/valid/newlines.c diff --git a/tests/week_1/valid/no_newlines.c b/stage_1/valid/no_newlines.c similarity index 100% rename from tests/week_1/valid/no_newlines.c rename to stage_1/valid/no_newlines.c diff --git a/tests/week_1/valid/return_0.c b/stage_1/valid/return_0.c similarity index 100% rename from tests/week_1/valid/return_0.c rename to stage_1/valid/return_0.c diff --git a/tests/week_1/valid/return_2.c b/stage_1/valid/return_2.c similarity index 100% rename from tests/week_1/valid/return_2.c rename to stage_1/valid/return_2.c diff --git a/tests/week_1/valid/spaces.c b/stage_1/valid/spaces.c similarity index 100% rename from tests/week_1/valid/spaces.c rename to stage_1/valid/spaces.c diff --git a/test_compiler.sh b/test_compiler.sh new file mode 100755 index 0000000..ccc485a --- /dev/null +++ b/test_compiler.sh @@ -0,0 +1,158 @@ +#!/bin/bash + +padding_dots=$(printf '%0.1s' "."{1..60}) +padlength=50 +cmp=$1 +success_total=0 +failure_total=0 + +print_test_name () { + test_name=$1 + printf '%s' "$test_name" + printf '%*.*s' 0 $((padlength - ${#test_name})) "$padding_dots" +} + +test_success () { + echo "OK" + ((success++)) +} + +test_failure () { + echo "FAIL" + ((fail++)) +} + +test_not_implemented () { + echo "NOT IMPLEMENTED" +} + +run_our_program () { + actual_out=`./$1 2>/dev/null` + actual_exit_code=$? + rm $1 2>/dev/null +} + +run_correct_program () { + expected_out=`./a.out` + expected_exit_code=$? + rm a.out +} + +compare_program_results () { + # make sure exit code is correct + if [ "$expected_exit_code" -ne "$actual_exit_code" ] || [ "$expected_out" != "$actual_out" ] + then + test_failure + else + test_success + fi +} + +test_stage () { + success=0 + fail=0 + echo "====================================================" + echo "STAGE $1" + echo "===================Valid Programs===================" + for prog in `find . -type f -name "*.c" -path "./stage_$1/valid/*" -not -path "*/valid_multifile/*" 2>/dev/null`; do + + gcc -w $prog + run_correct_program + + base="${prog%.*}" #name of executable (filename w/out extension) + test_name="${base##*valid/}" + + print_test_name $test_name + $cmp $prog 2>/dev/null + status=$? + + if [[ $test_name == "skip_on_failure"* ]]; then + # this may depend on features we haven't implemented yet + # if compilation succeeds, make sure it gives the right result + # otherwise don't count it as success or failure + if [[ -f $base ]] && [[ $status -eq 0 ]]; then + # it succeeded, so run it and make sure it gives the right result + run_our_program $base + compare_program_results + else + test_not_implemented + fi + else + run_our_program $base + compare_program_results + fi + done + # programs with multiple source files + for dir in `ls -d stage_$1/valid_multifile/* 2>/dev/null` ; do + gcc -w $dir/* + + run_correct_program + + base="${dir%.*}" #name of executable (directory w/out extension) + test_name="${base##*valid_multifile/}" + + # need to explicitly specify output name + $cmp -o "$test_name" $dir/* >/dev/null + + print_test_name $test_name + + # check output/exit codes + run_our_program $test_name + compare_program_results + + done + echo "===================Invalid Programs=================" + for prog in `ls stage_$1/invalid/{,**/}*.c 2>/dev/null`; do + + base="${prog%.*}" #name of executable (filename w/out extension) + test_name="${base##*invalid/}" + + $cmp $prog >/dev/null 2>&1 + status=$? #failed, as we expect, if exit code != 0 + print_test_name $test_name + + # make sure neither executable nor assembly was produced + # and exit code is non-zero + if [[ -f $base || -f $base".s" ]] + then + test_failure + rm $base 2>/dev/null + rm $base".s" 2>/dev/null + else + test_success + fi + done + echo "===================Stage $1 Summary=================" + printf "%d successes, %d failures\n" $success $fail + ((success_total=success_total+success)) + ((failure_total=failure_total + fail)) +} + +total_summary () { + echo "===================TOTAL SUMMARY====================" + printf "%d successes, %d failures\n" $success_total $failure_total +} + +if [ "$1" == "" ]; then + echo "USAGE: ./test_compiler.sh /path/to/compiler [stages(optional)]" + echo "EXAMPLE(test specific stages): ./test_compiler.sh ./mycompiler 1 2 4" + echo "EXAMPLE(test all): ./test_compiler.sh ./mycompiler" + exit 1 +fi + +if test 1 -lt $#; then + testcases=("$@") # [1..-1] is testcases + for i in `seq 2 $#`; do + test_stage ${testcases[$i-1]} + done + total_summary + exit 0 +fi + +num_stages=10 + +for i in `seq 1 $num_stages`; do + test_stage $i +done + +total_summary