Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Fiwo735 committed Mar 14, 2024
2 parents d501f9f + 0b74087 commit 06a6f6e
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 57 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
bin/
build/
.vscode
*.o
*.tab.hpp
Expand Down
44 changes: 17 additions & 27 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
# Based on https://stackoverflow.com/a/52036564 which is well worth reading!

CXXFLAGS += -std=c++20 -W -Wall -g -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -fsanitize=address -static-libasan -O0 -rdynamic -I include
CXXFLAGS += -std=c++20 -W -Wall -g -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -fsanitize=address -static-libasan -O0 -rdynamic --coverage -I include

SOURCES := $(wildcard src/*.cpp)
DEPENDENCIES := $(patsubst %.cpp,%.d,$(SOURCES))
DEPENDENCIES := $(patsubst src/%.cpp,build/%.d,$(SOURCES))

OBJECTS := $(patsubst %.cpp,%.o,$(SOURCES))
OBJECTS += src/parser.tab.o src/lexer.yy.o
OBJECTS := $(patsubst src/%.cpp,build/%.o,$(SOURCES))
OBJECTS += build/parser.tab.o build/lexer.yy.o


.PHONY: default clean with_coverage coverage
.PHONY: default clean coverage

default: bin/c_compiler

Expand All @@ -19,35 +18,26 @@ bin/c_compiler: $(OBJECTS)

-include $(DEPENDENCIES)

%.o: %.cpp Makefile
build/%.o: src/%.cpp Makefile
@mkdir -p $(@D)
g++ $(CXXFLAGS) -MMD -MP -c $< -o $@

src/parser.tab.cpp src/parser.tab.hpp: src/parser.y
bison -v -d src/parser.y -o src/parser.tab.cpp

src/lexer.yy.cpp : src/lexer.flex src/parser.tab.hpp
flex -o src/lexer.yy.cpp src/lexer.flex
build/parser.tab.cpp build/parser.tab.hpp: src/parser.y
@mkdir -p build
bison -v -d src/parser.y -o build/parser.tab.cpp

with_coverage : CXXFLAGS += --coverage
with_coverage : bin/c_compiler
build/lexer.yy.cpp: src/lexer.flex build/parser.tab.hpp
@mkdir -p build
flex -o build/lexer.yy.cpp src/lexer.flex

coverage : coverage/index.html

coverage/index.html :
coverage:
@rm -rf coverage/
@mkdir -p coverage
# somehow lexer and parser coverage info are available but not accurate. To exclude them use:
# lcov -c --no-external --exclude "`pwd`/src/lexer.*" --exclude "`pwd`/src/parser.*" -d . -o coverage/cov.info
lcov -c --no-external -d . -o coverage/cov.info
lcov -c --no-external --exclude "`pwd`/src/lexer.*" --exclude "`pwd`/src/parser.*" --exclude "`pwd`/build/*" -d . -o coverage/cov.info
genhtml coverage/cov.info -o coverage
@find . -name "*.gcda" -delete

clean :
@rm -rf coverage/
@rm -rf src/*.o
@rm -rf src/*.d
@rm -rf src/*.gcno
@rm -rf build/
@rm -rf bin/
@rm -f src/*.tab.hpp
@rm -f src/*.tab.cpp
@rm -f src/*.yy.cpp
@rm -f src/*.output
1 change: 1 addition & 0 deletions docs/c_compiler.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ Here is a list of intermediate features that you might like to implement once th
* the `enum` keyword
* `switch` statements
* the `break` and `continue` keywords
* ternary operator (`x ? y : z`)

Here is a list of more advanced features like you might like to implement once the basic and intermediate features are working.

Expand Down
2 changes: 1 addition & 1 deletion docs/coverage.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Coverage information
====================

If you want to know which part of your code is executed when running your compiler on a file you can build your compiler with `make with_coverage`, run your compiler on the file, then run `make coverage`.
If you want to know which part of your code is executed when running your compiler on a file you can run your compiler on the file, then run `make coverage`.

This will generate a webpage `coverage/index.html` with a listing of all the source files and for each source file a listing of the number of times each line has been executed.

Expand Down
69 changes: 50 additions & 19 deletions scripts/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
This script will also generate a JUnit XML file, which can be used to integrate
with CI/CD pipelines.
Usage: test.py [-h] [-m] [-s] [--version] [--no_clean | --coverage] [dir]
Usage: test.py [-h] [-m] [-s] [--version] [--no_clean] [--coverage] [dir]
Example usage: scripts/test.py compiler_tests/_example
Expand All @@ -32,6 +32,7 @@
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor, as_completed
from typing import List, Optional
from http.server import HTTPServer, SimpleHTTPRequestHandler


RED = "\033[31m"
Expand Down Expand Up @@ -321,29 +322,56 @@ def clean() -> bool:
return False
return True

def make(with_coverage: bool, silent: bool) -> bool:
def make(silent: bool) -> bool:
"""
Wrapper for make bin/c_compiler.
Return True if successful, False otherwise
"""
print(GREEN + "Running make..." + RESET)
return_code, error_msg, _ = run_subprocess(
cmd=["make", "-C", PROJECT_LOCATION, "bin/c_compiler"], timeout=BUILD_TIMEOUT_SECONDS, silent=silent
)
if return_code != 0:
print(RED + "Error when making:", error_msg + RESET)
return False

cmd = ["make", "-C", PROJECT_LOCATION, "bin/c_compiler"]
if with_coverage:
# Run coverage if needed
print(GREEN + "Making with coverage..." + RESET)
shutil.rmtree(COVERAGE_FOLDER, ignore_errors=True)
cmd = ["make", "-C", PROJECT_LOCATION, "with_coverage"]
return True

return_code, error_msg, _ = run_subprocess(cmd=cmd, timeout=BUILD_TIMEOUT_SECONDS, silent=silent)
def coverage() -> bool:
"""
Wrapper for make coverage.
Return True if successful, False otherwise
"""
print(GREEN + "Running make coverage..." + RESET)
return_code, error_msg, _ = run_subprocess(
cmd=["make", "-C", PROJECT_LOCATION, "coverage"], timeout=BUILD_TIMEOUT_SECONDS, silent=True
)
if return_code != 0:
print(RED + "Error when making:", error_msg + RESET)
print(RED + "Error when making coverage:", error_msg + RESET)
return False

return True

def serve_coverage_forever(host: str, port: int):
"""
Starts a HTTP server which serves the coverage folder forever until Ctrl+C
is pressed.
"""
class Handler(SimpleHTTPRequestHandler):
def __init__(self, *args, directory=None, **kwargs):
super().__init__(*args, directory=COVERAGE_FOLDER, **kwargs)

def log_message(self, format, *args):
pass

httpd = HTTPServer((host, port), Handler)
print(GREEN + "Serving coverage on" + RESET + f" http://{host}:{port}/ ... (Ctrl+C to exit)")
try:
httpd.serve_forever()
except KeyboardInterrupt:
print(RED + "\nServer has been stopped!" + RESET)

def process_result(
result: Result,
xml_file: JUnitXMLFile,
Expand Down Expand Up @@ -402,7 +430,7 @@ def run_tests(args, xml_file: JUnitXMLFile):
print("\n>> Test Summary: " + GREEN + f"{passing} Passed, " + RED + f"{total-passing} Failed" + RESET)

def parse_args():
""""
"""
Wrapper for argument parsing.
"""
parser = argparse.ArgumentParser()
Expand Down Expand Up @@ -433,16 +461,14 @@ def parse_args():
action="version",
version=f"BetterTesting {__version__}"
)
# Coverage cannot be perfomed without rebuilding the compiler
group = parser.add_mutually_exclusive_group(required=False)
group.add_argument(
"--no_clean",
parser.add_argument(
'--no_clean',
action="store_true",
default=False,
help="Do no clean the repository before testing. This will make it "
help="Don't clean the repository before testing. This will make it "
"faster but it can be safer to clean if you have any compilation issues."
)
group.add_argument(
parser.add_argument(
"--coverage",
action="store_true",
default=False,
Expand All @@ -461,12 +487,17 @@ def main():
# Clean the repo if required and exit if this fails.
exit(2)

if not make(with_coverage=args.coverage, silent=args.short):
if not make(silent=args.short):
exit(3)

with JUnitXMLFile(J_UNIT_OUTPUT_FILE) as xml_file:
run_tests(args, xml_file)

if args.coverage:
if not coverage():
exit(4)
serve_coverage_forever('0.0.0.0', 8000)

if __name__ == "__main__":
try:
main()
Expand Down
13 changes: 3 additions & 10 deletions scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,9 @@ if [ "${DONT_CLEAN:-}" != "1" ]; then
make clean
fi

if [ "${COVERAGE:-}" == "1" ]; then
rm -rf coverage
set -e
make with_coverage
set +e
else
set -e
make bin/c_compiler
set +e
fi
set -e
make bin/c_compiler
set +e

mkdir -p bin
mkdir -p bin/output
Expand Down
3 changes: 3 additions & 0 deletions src/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
extern FILE *yyin;
int yylex(void);
void yyerror(const char *);
int yylex_destroy(void);
}

// Represents the value associated with any kind of AST node.
Expand Down Expand Up @@ -202,5 +203,7 @@ Node *ParseAST(std::string file_name)
}
g_root = nullptr;
yyparse();
fclose(yyin);
yylex_destroy();
return g_root;
}
3 changes: 3 additions & 0 deletions src/parser_full.y.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
extern FILE *yyin;
int yylex(void);
void yyerror(const char *);
int yylex_destroy(void);
}

// Represents the value associated with any kind of AST node.
Expand Down Expand Up @@ -468,5 +469,7 @@ Node *ParseAST(std::string file_name)
}
g_root = nullptr;
yyparse();
fclose(yyin);
yylex_destroy();
return g_root;
}

0 comments on commit 06a6f6e

Please sign in to comment.