Compare commits
9 Commits
df9ebe0a3b
...
293c52d967
Author | SHA1 | Date | |
---|---|---|---|
293c52d967 | |||
|
f488adc39b | ||
|
316d71c5cc | ||
|
ac51b2cc1d | ||
|
206c6272df | ||
|
f164364595 | ||
|
ec0fe5ddb4 | ||
|
b0f49c056d | ||
|
587924218a |
34
PLANNING.md
34
PLANNING.md
@ -103,13 +103,45 @@ _Academic first semester 2024-2025_
|
|||||||
|
|
||||||
- :hammer: Lab 5b (2/2): Monday 18/11/2024, 13h30-15h30. Room E001 (Samuel Humeau & Emma Nardino)
|
- :hammer: Lab 5b (2/2): Monday 18/11/2024, 13h30-15h30. Room E001 (Samuel Humeau & Emma Nardino)
|
||||||
|
|
||||||
|
- :book: Course: Thursday 21/11/2024, 10h15-12h15. Amphi J (Yannick Zakowski)
|
||||||
|
|
||||||
|
* Functions: code generation [slides in english](course/cap_cours08_func_codegen.pdf).
|
||||||
|
|
||||||
# Week 10:
|
# Week 10:
|
||||||
|
|
||||||
- :notebook: TD: Monday 25/11/2024, 13h30-15h30. Room E001 (Samuel Humeau & Emma Nardino)
|
- :notebook: TD: Monday 25/11/2024, 13h30-15h30. Room E001 (Samuel Humeau & Emma Nardino)
|
||||||
|
|
||||||
|
- :book: Course: Thursday 28/11/2024, 10h15-12h15. Amphi B (Yannick Zakowski)
|
||||||
|
|
||||||
|
* Functions: semantics [slides in english](course/cap_cour309_func_semantics.pdf).
|
||||||
|
|
||||||
# Week 11:
|
# Week 11:
|
||||||
|
|
||||||
- :hammer: Choice Lab (1/3): Monday 02/12/2024, 8h00-13h30. Room E001 (Samuel Humeau & Emma Nardino)
|
- :hammer: Choice Lab (1/3): Monday 02/12/2024, 8h00-13h30. Room E001 (Samuel Humeau & Emma Nardino)
|
||||||
|
|
||||||
* Optimisations under SSA form [TP5c](TP05/tp5c.pdf), code in [MiniC/TPoptim/](MiniC/TPoptim/).
|
* Optimisations under SSA form [TP5c](TP05/tp5c.pdf), code in [MiniC/TPoptim/](MiniC/TPoptim/).
|
||||||
* Other possibilities next week.
|
* Parsing and typechecking functions [TP06a](TP06/tp6a.pdf), code in [MiniC/](MiniC/).
|
||||||
|
* Code generation for functions [TP06b](TP06/tp6b.pdf), code in [MiniC/](MiniC/).
|
||||||
|
|
||||||
|
- :book: Course: Thursday 05/12/2024, 10h15-12h15. Amphi B (Yannick Zakowski)
|
||||||
|
|
||||||
|
* On parallelism [slides in english](course/cap_cours10_parallelism.pdf).
|
||||||
|
|
||||||
|
# Week 12:
|
||||||
|
|
||||||
|
- :hammer: Choice Lab (2/3): Thursday 09/12/2024, 13h30-15h30. Room E001 (Samuel Humeau & Emma Nardino)
|
||||||
|
|
||||||
|
* Optimisations under SSA form [TP5c](TP05/tp5c.pdf), code in [MiniC/TPoptim/](MiniC/TPoptim/).
|
||||||
|
* Parsing and typechecking functions [TP06a](TP06/tp6a.pdf), code in [MiniC/](MiniC/).
|
||||||
|
* Code generation for functions [TP06b](TP06/tp6b.pdf), code in [MiniC/](MiniC/).
|
||||||
|
* Going Parallel with futures [TPfutures](TPfutures/tpfutures.pdf), code in [TPfutures/MiniC-futures/](TPfutures/MiniC-futures/).
|
||||||
|
|
||||||
|
- :book: Course: Thursday 12/12/2024, 10h15-12h15. Amphi B (Yannick Zakowski)
|
||||||
|
|
||||||
|
* Verified Compilation [introduction slides](course/cap_cours11_verified.pdf).
|
||||||
|
* Course on black board
|
||||||
|
* Additional resources: [Xavier Leroy's class at Collège de France](https://www.college-de-france.fr/en/agenda/lecture/mechanized-semantics-when-the-machine-reasons-about-its-languages)
|
||||||
|
|
||||||
|
# Week 13:
|
||||||
|
|
||||||
|
- :hammer: Choice Lab (3/3): Monday 16/12/2024, 13h30-15h30. Room E001 (Samuel Humeau & Emma Nardino)
|
||||||
|
BIN
TP06/tp6a.pdf
Normal file
BIN
TP06/tp6a.pdf
Normal file
Binary file not shown.
BIN
TP06/tp6b.pdf
Normal file
BIN
TP06/tp6b.pdf
Normal file
Binary file not shown.
15
TPfutures/MiniC-futures/.gitignore
vendored
Normal file
15
TPfutures/MiniC-futures/.gitignore
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/MiniCLexer.py
|
||||||
|
/MiniCParser.py
|
||||||
|
/MiniCVisitor.py
|
||||||
|
/MiniCListener.py
|
||||||
|
*.dot
|
||||||
|
*.dot.pdf
|
||||||
|
*.riscv
|
||||||
|
*-naive.s
|
||||||
|
*-gcc.s
|
||||||
|
*-all_in_mem.s
|
||||||
|
*-smart.s
|
||||||
|
*.cfut
|
||||||
|
*.o
|
||||||
|
/MiniC.interp
|
||||||
|
/MiniCLexer.interp
|
14
TPfutures/MiniC-futures/Errors.py
Normal file
14
TPfutures/MiniC-futures/Errors.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
class MiniCRuntimeError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MiniCInternalError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MiniCUnsupportedError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MiniCTypeError(Exception):
|
||||||
|
pass
|
56
TPfutures/MiniC-futures/Makefile
Normal file
56
TPfutures/MiniC-futures/Makefile
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
PACKAGE = MiniC
|
||||||
|
# Example: stop at the first failed test:
|
||||||
|
# make PYTEST_OPTS=-x tests
|
||||||
|
PYTEST_OPTS =
|
||||||
|
# Run the whole test infrastructure for a subset of test files e.g.
|
||||||
|
# make TEST_FILES='TP03/**/bad*.c' tests
|
||||||
|
ifdef TEST_FILES
|
||||||
|
export TEST_FILES
|
||||||
|
endif
|
||||||
|
|
||||||
|
PYTEST_BASE_OPTS=-vv -rs --failed-first --cov="$(PWD)" --cov-report=term --cov-report=html
|
||||||
|
|
||||||
|
ifndef ANTLR4
|
||||||
|
abort:
|
||||||
|
$(error variable ANTLR4 is not set)
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: antlr
|
||||||
|
|
||||||
|
.PHONY: antlr
|
||||||
|
antlr MiniCLexer.py MiniCParser.py: $(PACKAGE).g4
|
||||||
|
$(ANTLR4) $< -Dlanguage=Python3 -visitor
|
||||||
|
|
||||||
|
main-deps: MiniCLexer.py MiniCParser.py MiniCTypingVisitor.py MiniCPPListener.py
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS)
|
||||||
|
gcc -g -c -Wall -Wextra $< -o $@
|
||||||
|
|
||||||
|
$(TESTFILE:%.c=%.o): $(TESTFILE:%.c=%.cfut) $(HEADERS)
|
||||||
|
gcc -g -c -Iinclude -Wall -Wextra -x c $(TESTFILE:%.c=%.cfut) -o $(TESTFILE:%.c=%.o)
|
||||||
|
|
||||||
|
$(TESTFILE:%.c=%.out): $(TESTFILE:%.c=%.o) lib/futurelib.o
|
||||||
|
gcc -g $(TESTFILE:%.c=%.o) lib/futurelib.o -o $(TESTFILE:%.c=%.out) -lpthread
|
||||||
|
|
||||||
|
$(TESTFILE:%.c=%.cfut): main-deps
|
||||||
|
python3 MiniCC.py $(TESTFILE)
|
||||||
|
|
||||||
|
run: $(TESTFILE:%.c=%.out)
|
||||||
|
$(TESTFILE:%.c=%.out)
|
||||||
|
|
||||||
|
test: test_futures.py main-deps
|
||||||
|
python3 -m pytest $(PYTEST_BASE_OPTS) $(PYTEST_OPTS) ./test_futures.py
|
||||||
|
|
||||||
|
tar: clean
|
||||||
|
dir=$$(basename "$$PWD") && cd .. && \
|
||||||
|
tar cvfz "$$dir.tgz" --exclude="*.riscv" --exclude=".git" --exclude=".pytest_cache" \
|
||||||
|
--exclude="htmlcov" "$$dir"
|
||||||
|
@echo "Created ../$$(basename "$$PWD").tgz"
|
||||||
|
|
||||||
|
clean-tests:
|
||||||
|
cd tests && \
|
||||||
|
find . \( -iname "*.cfut" -or -iname "*.out" \) -print0 | xargs -0 rm -rf \;
|
||||||
|
|
||||||
|
clean: clean-tests
|
||||||
|
find . \( -iname "*~" -or -iname ".cache*" -or -iname "*.diff" -or -iname "log*.txt" -or -iname "__pycache__" -or -iname "*.tokens" -or -iname "*.interp" -or -iname "*.o" \) -print0 | xargs -0 rm -rf \;
|
||||||
|
rm -rf *~ $(PACKAGE)Parser.py $(PACKAGE)Lexer.py $(PACKAGE)Visitor.py $(PACKAGE)Listener.py .coverage .benchmarks
|
164
TPfutures/MiniC-futures/MiniC.g4
Normal file
164
TPfutures/MiniC-futures/MiniC.g4
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
grammar MiniC;
|
||||||
|
|
||||||
|
prog: include* function* EOF #progRule;
|
||||||
|
|
||||||
|
//include statements reduced to string
|
||||||
|
include: INCLUDE STRING #includestat ;
|
||||||
|
|
||||||
|
function
|
||||||
|
: typee ID OPAR param_l? CPAR OBRACE vardecl_l block RETURN expr SCOL CBRACE #funcDef
|
||||||
|
| typee ID OPAR param_l? CPAR SCOL #funcDecl
|
||||||
|
;
|
||||||
|
|
||||||
|
vardecl_l: vardecl* #varDeclList;
|
||||||
|
|
||||||
|
vardecl: typee id_l SCOL #varDecl;
|
||||||
|
|
||||||
|
param: typee ID #paramDecl;
|
||||||
|
|
||||||
|
param_l
|
||||||
|
: param #paramListBase
|
||||||
|
| param COM param_l #paramList
|
||||||
|
;
|
||||||
|
|
||||||
|
id_l
|
||||||
|
: ID #idListBase
|
||||||
|
| ID COM id_l #idList
|
||||||
|
;
|
||||||
|
|
||||||
|
block: stat* #statList;
|
||||||
|
|
||||||
|
stat
|
||||||
|
: assignment SCOL
|
||||||
|
| if_stat
|
||||||
|
| while_stat
|
||||||
|
| print_stat
|
||||||
|
;
|
||||||
|
|
||||||
|
assignment: ID ASSIGN expr #assignStat;
|
||||||
|
|
||||||
|
if_stat: IF OPAR expr CPAR then_block=stat_block (ELSE else_block=stat_block)? #ifStat;
|
||||||
|
|
||||||
|
stat_block
|
||||||
|
: OBRACE block CBRACE
|
||||||
|
| stat
|
||||||
|
;
|
||||||
|
|
||||||
|
while_stat: WHILE OPAR expr CPAR body=stat_block #whileStat;
|
||||||
|
|
||||||
|
|
||||||
|
print_stat
|
||||||
|
: PRINTINT OPAR expr CPAR SCOL #printlnintStat
|
||||||
|
| PRINTFLOAT OPAR expr CPAR SCOL #printlnfloatStat
|
||||||
|
| PRINTBOOL OPAR expr CPAR SCOL #printlnboolStat
|
||||||
|
| PRINTSTRING OPAR expr CPAR SCOL #printstringStat
|
||||||
|
;
|
||||||
|
|
||||||
|
expr_l
|
||||||
|
: expr #exprListBase
|
||||||
|
| expr COM expr_l #exprList
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
expr
|
||||||
|
: MINUS expr #unaryMinusExpr
|
||||||
|
| NOT expr #notExpr
|
||||||
|
| expr myop=(MULT|DIV|MOD) expr #multiplicativeExpr
|
||||||
|
| expr myop=(PLUS|MINUS) expr #additiveExpr
|
||||||
|
| expr myop=(GT|LT|GTEQ|LTEQ) expr #relationalExpr
|
||||||
|
| expr myop=(EQ|NEQ) expr #equalityExpr
|
||||||
|
| expr AND expr #andExpr
|
||||||
|
| expr OR expr #orExpr
|
||||||
|
| ID OPAR expr_l? CPAR #funcCall
|
||||||
|
| GET OPAR expr CPAR #getCall
|
||||||
|
| ASYNC OPAR ID COM expr_l? CPAR #asyncFuncCall
|
||||||
|
| atom #atomExpr
|
||||||
|
;
|
||||||
|
|
||||||
|
atom
|
||||||
|
: OPAR expr CPAR #parExpr
|
||||||
|
| INT #intAtom
|
||||||
|
| FLOAT #floatAtom
|
||||||
|
| (TRUE | FALSE) #booleanAtom
|
||||||
|
| ID #idAtom
|
||||||
|
| STRING #stringAtom
|
||||||
|
;
|
||||||
|
|
||||||
|
typee
|
||||||
|
: mytype=(INTTYPE|FLOATTYPE|BOOLTYPE|STRINGTYPE|FUTINTTYPE) #basicType
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
ASYNC : 'Async';
|
||||||
|
GET : 'Get';
|
||||||
|
OR : '||';
|
||||||
|
AND : '&&';
|
||||||
|
EQ : '==';
|
||||||
|
NEQ : '!=';
|
||||||
|
GT : '>';
|
||||||
|
LT : '<';
|
||||||
|
GTEQ : '>=';
|
||||||
|
LTEQ : '<=';
|
||||||
|
PLUS : '+';
|
||||||
|
MINUS : '-';
|
||||||
|
MULT : '*';
|
||||||
|
DIV : '/';
|
||||||
|
MOD : '%';
|
||||||
|
NOT : '!';
|
||||||
|
|
||||||
|
COL: ':';
|
||||||
|
SCOL : ';';
|
||||||
|
COM : ',';
|
||||||
|
ASSIGN : '=';
|
||||||
|
OPAR : '(';
|
||||||
|
CPAR : ')';
|
||||||
|
OBRACE : '{';
|
||||||
|
CBRACE : '}';
|
||||||
|
|
||||||
|
TRUE : 'true';
|
||||||
|
FALSE : 'false';
|
||||||
|
IF : 'if';
|
||||||
|
ELSE : 'else';
|
||||||
|
WHILE : 'while';
|
||||||
|
RETURN : 'return';
|
||||||
|
PRINTINT : 'println_int';
|
||||||
|
PRINTBOOL : 'println_bool';
|
||||||
|
PRINTSTRING : 'println_string';
|
||||||
|
PRINTFLOAT : 'println_float';
|
||||||
|
|
||||||
|
FUTINTTYPE: 'futint';
|
||||||
|
INTTYPE: 'int';
|
||||||
|
FLOATTYPE: 'float';
|
||||||
|
STRINGTYPE: 'string';
|
||||||
|
BOOLTYPE : 'bool';
|
||||||
|
INCLUDE : '#include';
|
||||||
|
|
||||||
|
ID
|
||||||
|
: [a-zA-Z_] [a-zA-Z_0-9]*
|
||||||
|
;
|
||||||
|
|
||||||
|
INT
|
||||||
|
: [0-9]+
|
||||||
|
;
|
||||||
|
|
||||||
|
FLOAT
|
||||||
|
: [0-9]+ '.' [0-9]*
|
||||||
|
| '.' [0-9]+
|
||||||
|
;
|
||||||
|
|
||||||
|
STRING
|
||||||
|
: '"' (~["\r\n] | '""')* '"'
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
COMMENT
|
||||||
|
// # is a comment in Mini-C, and used for #include in real C so that we ignore #include statements
|
||||||
|
// BUT now we want to keep includes => # removed
|
||||||
|
: '//' ~[\r\n]* -> skip
|
||||||
|
;
|
||||||
|
|
||||||
|
SPACE
|
||||||
|
// here is a little for code rewriting.
|
||||||
|
: [ \t\r\n] -> channel(HIDDEN)
|
||||||
|
;
|
||||||
|
|
112
TPfutures/MiniC-futures/MiniCC.py
Normal file
112
TPfutures/MiniC-futures/MiniCC.py
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
"""
|
||||||
|
MiniC-futures Lab. Language Extension for MiniC with future primitives
|
||||||
|
Usage:
|
||||||
|
python3 Main.py <filename>
|
||||||
|
python3 Main.py --help
|
||||||
|
"""
|
||||||
|
import traceback
|
||||||
|
from MiniCLexer import MiniCLexer
|
||||||
|
from MiniCParser import MiniCParser
|
||||||
|
from MiniCTypingVisitor import MiniCTypingVisitor, MiniCTypeError
|
||||||
|
from MiniCPPListener import MiniCPPListener
|
||||||
|
from Errors import MiniCUnsupportedError, MiniCInternalError
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
from antlr4 import FileStream, CommonTokenStream, ParseTreeWalker
|
||||||
|
from antlr4.error.ErrorListener import ErrorListener
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
class CountErrorListener(ErrorListener):
|
||||||
|
"""Count number of errors.
|
||||||
|
|
||||||
|
Parser provides getNumberOfSyntaxErrors(), but the Lexer
|
||||||
|
apparently doesn't provide an easy way to know if an error occured
|
||||||
|
after the fact. Do the counting ourserves with a listener.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(CountErrorListener, self).__init__()
|
||||||
|
self.count = 0
|
||||||
|
|
||||||
|
def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
|
||||||
|
self.count += 1
|
||||||
|
|
||||||
|
|
||||||
|
def main(inputname,
|
||||||
|
typecheck=True, typecheck_only=False, stdout=False, output_name=None, debug=False):
|
||||||
|
(basename, rest) = os.path.splitext(inputname)
|
||||||
|
if not typecheck_only:
|
||||||
|
if stdout:
|
||||||
|
output_name = None
|
||||||
|
elif output_name is None:
|
||||||
|
output_name = basename + ".cfut"
|
||||||
|
|
||||||
|
input_s = FileStream(inputname, encoding='utf-8')
|
||||||
|
lexer = MiniCLexer(input_s)
|
||||||
|
counter = CountErrorListener()
|
||||||
|
lexer._listeners.append(counter)
|
||||||
|
stream = CommonTokenStream(lexer)
|
||||||
|
parser = MiniCParser(stream)
|
||||||
|
parser._listeners.append(counter)
|
||||||
|
tree = parser.prog()
|
||||||
|
if counter.count > 0:
|
||||||
|
exit(3) # Syntax or lexicography errors occurred, don't try to go further.
|
||||||
|
|
||||||
|
if typecheck:
|
||||||
|
typing_visitor = MiniCTypingVisitor()
|
||||||
|
try:
|
||||||
|
typing_visitor.visit(tree)
|
||||||
|
except MiniCTypeError as e:
|
||||||
|
print(e.args[0])
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
if typecheck_only:
|
||||||
|
if debug:
|
||||||
|
print("Not running code generation because of --disable-codegen.")
|
||||||
|
return
|
||||||
|
|
||||||
|
pw = ParseTreeWalker()
|
||||||
|
extractor = MiniCPPListener(stream)
|
||||||
|
pw.walk(extractor, tree)
|
||||||
|
with open(output_name, 'w') if output_name else sys.stdout as output:
|
||||||
|
extractor.printrw(output)
|
||||||
|
|
||||||
|
|
||||||
|
# command line management
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser(description='Generate code for .c file')
|
||||||
|
|
||||||
|
parser.add_argument('filename', type=str,
|
||||||
|
help='Source file.')
|
||||||
|
parser.add_argument('--stdout', action='store_true',
|
||||||
|
help='Generate code to stdout')
|
||||||
|
parser.add_argument('--debug', action='store_true',
|
||||||
|
default=False,
|
||||||
|
help='Emit verbose debug output')
|
||||||
|
parser.add_argument('--disable-typecheck', action='store_true',
|
||||||
|
default=False,
|
||||||
|
help="Don't run the typechecker before generating code")
|
||||||
|
parser.add_argument('--disable-codegen', action='store_true',
|
||||||
|
default=False,
|
||||||
|
help="Run only the typechecker, don't try generating code.")
|
||||||
|
parser.add_argument('--output', type=str,
|
||||||
|
help='Generate code to outfile')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
main(args.filename,
|
||||||
|
not args.disable_typecheck, args.disable_codegen,
|
||||||
|
args.stdout, args.output, args.debug,
|
||||||
|
)
|
||||||
|
except MiniCUnsupportedError as e:
|
||||||
|
print(e)
|
||||||
|
exit(5)
|
||||||
|
except (MiniCInternalError):
|
||||||
|
traceback.print_exc()
|
||||||
|
exit(4)
|
27
TPfutures/MiniC-futures/MiniCPPListener.py
Normal file
27
TPfutures/MiniC-futures/MiniCPPListener.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
from MiniCListener import MiniCListener
|
||||||
|
|
||||||
|
from antlr4.TokenStreamRewriter import TokenStreamRewriter
|
||||||
|
|
||||||
|
|
||||||
|
class MiniCPPListener(MiniCListener):
|
||||||
|
def __init__(self, t):
|
||||||
|
self.rewriter = TokenStreamRewriter(tokens=t)
|
||||||
|
|
||||||
|
def printrw(self, output):
|
||||||
|
output.write(self.rewriter.getText('default', 0, 1000))
|
||||||
|
|
||||||
|
def enterProgRule(self, ctx):
|
||||||
|
"""Adds an include futurelib.h at the beginning of program."""
|
||||||
|
indexprog = ctx.start.tokenIndex
|
||||||
|
self.rewriter.insertBeforeIndex(indexprog, '#include \"futurelib.h\"\n')
|
||||||
|
|
||||||
|
def exitFuncDef(self, ctx):
|
||||||
|
"""Adds a call to freeAllFutures at the end of the body of the main function."""
|
||||||
|
(indexret, endret) = ctx.RETURN().getSourceInterval()
|
||||||
|
if ctx.ID().getText() == "main":
|
||||||
|
self.rewriter.insertBeforeIndex(indexret, 'freeAllFutures();\n')
|
||||||
|
|
||||||
|
def enterAsyncFuncCall(self, ctx):
|
||||||
|
"""Adds a & for getting a function pointer to the asynchronous called function."""
|
||||||
|
indexfunid = ctx.start.tokenIndex # token of async
|
||||||
|
self.rewriter.insertBeforeIndex(indexfunid + 2, '&')
|
17
TPfutures/MiniC-futures/MiniCTypingVisitor.py
Normal file
17
TPfutures/MiniC-futures/MiniCTypingVisitor.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Visitor to *typecheck* MiniC files
|
||||||
|
from typing import List
|
||||||
|
from MiniCVisitor import MiniCVisitor
|
||||||
|
from MiniCParser import MiniCParser
|
||||||
|
from Lib.Errors import MiniCInternalError, MiniCTypeError
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
# NEW: ADD FutInteger
|
||||||
|
class BaseType(Enum):
|
||||||
|
Float, Integer, Boolean, String, FutInteger = range(5)
|
||||||
|
|
||||||
|
|
||||||
|
class MiniCTypingVisitor(MiniCVisitor):
|
||||||
|
# TODO Add your own typer here
|
||||||
|
pass
|
25
TPfutures/MiniC-futures/README.md
Normal file
25
TPfutures/MiniC-futures/README.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# MiniC Compiler
|
||||||
|
LAB8 (Futures) CAP 2022-23
|
||||||
|
|
||||||
|
# Authors
|
||||||
|
|
||||||
|
YOUR NAME HERE
|
||||||
|
|
||||||
|
# Contents
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
- Explain any design choices you may have made.
|
||||||
|
- Did you implement a bonus?
|
||||||
|
|
||||||
|
# Howto
|
||||||
|
|
||||||
|
`make run TESTFILE=tests/provided/test_fut0.c`: launch the compiler, then GCC and run a single file.
|
||||||
|
|
||||||
|
# Test design
|
||||||
|
|
||||||
|
TODO: explain your tests.
|
||||||
|
|
||||||
|
# Known bugs
|
||||||
|
|
||||||
|
TODO: bugs you could not fix (if any) and limitations.
|
||||||
|
|
12
TPfutures/MiniC-futures/include/compat.h
Normal file
12
TPfutures/MiniC-futures/include/compat.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#include "stdio.h"
|
||||||
|
|
||||||
|
typedef char * string;
|
||||||
|
typedef int bool;
|
||||||
|
static const int true = 1;
|
||||||
|
static const int false = 0;
|
||||||
|
|
||||||
|
void print_int(int i) {printf("%i",i);}
|
||||||
|
void println_int(int i) {printf("%i\n",i);}
|
||||||
|
|
||||||
|
void print_string(string);
|
||||||
|
void println_string(string);
|
34
TPfutures/MiniC-futures/include/futurelib.h
Normal file
34
TPfutures/MiniC-futures/include/futurelib.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
typedef struct // a struct for storing a future to int
|
||||||
|
{
|
||||||
|
int Id;
|
||||||
|
int Value;
|
||||||
|
int resolved;
|
||||||
|
pthread_t tid;
|
||||||
|
} FutureInt;
|
||||||
|
|
||||||
|
typedef FutureInt* futint; // a typedef to deal with the future type of MiniCFut
|
||||||
|
|
||||||
|
FutureInt *fresh_future_malloc(); // allocates (malloc) a fresh future and initializes its field
|
||||||
|
|
||||||
|
void print_futureInt(FutureInt *fut); // for debug purposes: print a fut int status
|
||||||
|
|
||||||
|
void free_future(FutureInt *fut); // frees the pointer allocated by fresh_future
|
||||||
|
|
||||||
|
void resolve_future(FutureInt *fut, int val); // function called when an async call is finished
|
||||||
|
|
||||||
|
int Get(FutureInt *fut);
|
||||||
|
// called by the main program:
|
||||||
|
// checks that the future is resolved and
|
||||||
|
// returns the value stored in the future
|
||||||
|
|
||||||
|
FutureInt *Async(int (*fun)(int), int p);
|
||||||
|
// asynchronous function call:
|
||||||
|
// takes a function pointer as parameter and the fun call parameter as second parameter
|
||||||
|
// returns an unresolved future
|
||||||
|
// creates a thread to perform the asynchronous function call
|
||||||
|
|
||||||
|
void freeAllFutures();
|
||||||
|
// called at the end of the main block: waits for the resolution of all futures
|
||||||
|
// and frees all future pointers created by fresh_future
|
77
TPfutures/MiniC-futures/lib/futurelib.c
Normal file
77
TPfutures/MiniC-futures/lib/futurelib.c
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "../include/futurelib.h"
|
||||||
|
|
||||||
|
FutureInt *All[70];
|
||||||
|
// A table of future pointers to store all the futures created
|
||||||
|
// In a realistic scenario this would be a dynamic structure
|
||||||
|
int NbAll = 0;
|
||||||
|
// Number of futures created
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
// A structure for the argument of thread creation: function pointer and parameter
|
||||||
|
{
|
||||||
|
FutureInt *fut;
|
||||||
|
int (*fun)(int);
|
||||||
|
int param;
|
||||||
|
} arg_struct;
|
||||||
|
|
||||||
|
FutureInt *fresh_future_malloc()
|
||||||
|
{
|
||||||
|
// TODO Exercise 4.2
|
||||||
|
// Use malloc(sizeof(FutureInt)) and reference created futures
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_futureInt(FutureInt *f)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
// For debug purposes only
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_future(FutureInt *fut)
|
||||||
|
{
|
||||||
|
free(fut);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolve_future(FutureInt *fut, int val)
|
||||||
|
{
|
||||||
|
// TODO Exercise 5.1
|
||||||
|
// Fill fut accordingly
|
||||||
|
}
|
||||||
|
|
||||||
|
int Get(FutureInt *fut)
|
||||||
|
{
|
||||||
|
// TODO Exercise 5.2
|
||||||
|
// Wait until future is resolved (do a sleep(1) between two checks)
|
||||||
|
// Do not forget to do a pthread_join(fut->tid, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *runTask(void *param)
|
||||||
|
{
|
||||||
|
// TODO Exercise 4.1
|
||||||
|
// function that is launched by the created thread: should call the function and
|
||||||
|
// deal with the future, using the function resolve_future
|
||||||
|
// param can be cast to (arg_struct *)
|
||||||
|
// this function should free the pointer param
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FutureInt *Async(int (*fun)(int), int p)
|
||||||
|
{
|
||||||
|
// TODO Exercise 4.3
|
||||||
|
// Main system call should be: int err = pthread_create(&fut->tid, NULL, &runTask, (args));
|
||||||
|
// Allocate a future and space for arguments: args = malloc(sizeof(arg_struct));
|
||||||
|
// Do not forget to populate args
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeAllFutures()
|
||||||
|
{
|
||||||
|
// TODO Exercises 4.4 & 5.3
|
||||||
|
// 1 - Wait for all futures (Get) to avoid dangling threads (Exercise 5.3)
|
||||||
|
// 2 - Call free_future for all futures (Exercise 4.4)
|
||||||
|
}
|
193
TPfutures/MiniC-futures/test_expect_pragma.py
Normal file
193
TPfutures/MiniC-futures/test_expect_pragma.py
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
import collections
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
testinfo = collections.namedtuple(
|
||||||
|
'testinfo',
|
||||||
|
['exitcode', 'execcode', 'output', 'linkargs', 'skip_test_expected'])
|
||||||
|
default_testinfo = testinfo(
|
||||||
|
exitcode=0, execcode=0, output='', linkargs=[], skip_test_expected=False)
|
||||||
|
|
||||||
|
|
||||||
|
def cat(filename):
|
||||||
|
with open(filename, "rb") as f:
|
||||||
|
for line in f:
|
||||||
|
sys.stdout.buffer.write(line)
|
||||||
|
|
||||||
|
|
||||||
|
def env_bool_variable(name, globals):
|
||||||
|
if name not in globals:
|
||||||
|
globals[name] = False
|
||||||
|
if name in os.environ:
|
||||||
|
globals[name] = True
|
||||||
|
|
||||||
|
|
||||||
|
def env_str_variable(name, globals):
|
||||||
|
if name in os.environ:
|
||||||
|
globals[name] = os.environ[name]
|
||||||
|
|
||||||
|
|
||||||
|
class TestExpectPragmas(object):
|
||||||
|
"""Base class for tests that read the expected result as annotations
|
||||||
|
in test files.
|
||||||
|
|
||||||
|
get_expect(file) will parse the file, looking EXPECT and EXITCODE
|
||||||
|
pragmas.
|
||||||
|
|
||||||
|
run_command(command) is a wrapper around subprocess.check_output()
|
||||||
|
that extracts the output and exit code.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_expect(self, filename):
|
||||||
|
"""Parse "filename" looking for EXPECT and EXITCODE annotations.
|
||||||
|
|
||||||
|
Look for a line "EXPECTED" (possibly with whitespaces and
|
||||||
|
comments). Text after this "EXPECTED" line is the expected
|
||||||
|
output.
|
||||||
|
|
||||||
|
The file may also contain a line like "EXITCODE <n>" where <n>
|
||||||
|
is an integer, and is the expected exitcode of the command.
|
||||||
|
|
||||||
|
The result is cached to avoid re-parsing the file multiple
|
||||||
|
times.
|
||||||
|
"""
|
||||||
|
if filename not in self.__expect:
|
||||||
|
self.__expect[filename] = self._extract_expect(filename)
|
||||||
|
return self.__expect[filename]
|
||||||
|
|
||||||
|
def remove(self, file):
|
||||||
|
"""Like os.remove(), but ignore errors, e.g. don't complain if the
|
||||||
|
file doesn't exist.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
os.remove(file)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def run_command(self, cmd, scope="compile"):
|
||||||
|
"""Run the command cmd (given as [command, arg1, arg2, ...]), and
|
||||||
|
return testinfo(exitcode=..., output=...) containing the
|
||||||
|
exit code of the command it its standard output + standard error.
|
||||||
|
|
||||||
|
If scope="compile" (resp. "runtime"), then the exitcode (resp.
|
||||||
|
execcode) is set with the exit status of the command, and the
|
||||||
|
execcode (resp. exitcode) is set to 0.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
output = subprocess.check_output(cmd, timeout=60,
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
status = 0
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
output = e.output
|
||||||
|
status = e.returncode
|
||||||
|
if scope == "runtime":
|
||||||
|
return default_testinfo._replace(execcode=status,
|
||||||
|
output=output.decode())
|
||||||
|
else:
|
||||||
|
return default_testinfo._replace(exitcode=status,
|
||||||
|
output=output.decode())
|
||||||
|
|
||||||
|
def skip_if_partial_match(self, actual, expect, ignore_error_message):
|
||||||
|
if not ignore_error_message:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# TODO: Deal with undefined behavior here?
|
||||||
|
|
||||||
|
if expect.exitcode != actual.exitcode:
|
||||||
|
# Not the same exit code => something's wrong anyway
|
||||||
|
return False
|
||||||
|
|
||||||
|
if actual.exitcode == 3:
|
||||||
|
# There's a syntax error in both expected and actual,
|
||||||
|
# but the actual error may slightly differ if we don't
|
||||||
|
# have the exact same .g4.
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Let the test pass with 'return True' if appropriate.
|
||||||
|
# Otherwise, continue to the full assertion for a
|
||||||
|
# complete diagnostic.
|
||||||
|
if actual.exitcode != 0 and expect.exitcode == actual.exitcode:
|
||||||
|
if expect.output == '':
|
||||||
|
# No output expected, but we know there must be an
|
||||||
|
# error. If there was a particular error message
|
||||||
|
# expected, we'd have written it in the output,
|
||||||
|
# hence just ignore the actual message.
|
||||||
|
return True
|
||||||
|
# Ignore difference in error message except in the
|
||||||
|
# line number (ignore the column too, it may
|
||||||
|
# slightly vary, eg. in "foo" / 4, the error may
|
||||||
|
# be considered on "foo" or on /):
|
||||||
|
if re.match(r'^In function [^ :]*: Line [0-9]* col [0-9]*:',
|
||||||
|
actual.output):
|
||||||
|
out_loc = re.sub(r' col [0-9]*:.*$', '', actual.output)
|
||||||
|
exp_loc = re.sub(r' col [0-9]*:.*$', '', expect.output)
|
||||||
|
if out_loc == exp_loc:
|
||||||
|
return True
|
||||||
|
if any(x.output and
|
||||||
|
(x.output.endswith('has no value yet!' + os.linesep)
|
||||||
|
or x.output.endswith(' by 0' + os.linesep))
|
||||||
|
for x in (actual, expect)):
|
||||||
|
# Ignore the error message when our compiler
|
||||||
|
# raises this error (either in actual or expect,
|
||||||
|
# depending on what we're testing).
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
__expect = {}
|
||||||
|
|
||||||
|
def _extract_expect(self, file):
|
||||||
|
exitcode = 0
|
||||||
|
execcode = 0
|
||||||
|
linkargs = []
|
||||||
|
inside_expected = False
|
||||||
|
skip_test_expected = False
|
||||||
|
expected_lines = []
|
||||||
|
expected_present = False
|
||||||
|
with open(file, encoding="utf-8") as f:
|
||||||
|
for line in f.readlines():
|
||||||
|
# Ignore non-comments
|
||||||
|
if not re.match(r'\s*//', line):
|
||||||
|
continue
|
||||||
|
# Cleanup comment start and whitespaces
|
||||||
|
line = re.sub(r'\s*//\s*', '', line)
|
||||||
|
line = re.sub(r'\s*$', '', line)
|
||||||
|
|
||||||
|
if line == 'END EXPECTED':
|
||||||
|
inside_expected = False
|
||||||
|
elif line.startswith('EXITCODE'):
|
||||||
|
words = line.split(' ')
|
||||||
|
assert len(words) == 2
|
||||||
|
exitcode = int(words[1])
|
||||||
|
elif line.startswith('EXECCODE'):
|
||||||
|
words = line.split(' ')
|
||||||
|
assert len(words) == 2
|
||||||
|
execcode = int(words[1])
|
||||||
|
elif line.startswith('LINKARGS'):
|
||||||
|
words = line.split(' ')
|
||||||
|
assert len(words) >= 2
|
||||||
|
linkargs += [w.replace("$dir", os.path.dirname(file))
|
||||||
|
for w in words[1:]]
|
||||||
|
elif line == 'EXPECTED':
|
||||||
|
inside_expected = True
|
||||||
|
expected_present = True
|
||||||
|
elif line == 'SKIP TEST EXPECTED':
|
||||||
|
skip_test_expected = True
|
||||||
|
elif inside_expected:
|
||||||
|
expected_lines.append(line)
|
||||||
|
|
||||||
|
if not expected_present:
|
||||||
|
pytest.fail("Missing EXPECTED directive in test file")
|
||||||
|
|
||||||
|
if expected_lines == []:
|
||||||
|
output = ''
|
||||||
|
else:
|
||||||
|
output = os.linesep.join(expected_lines) + os.linesep
|
||||||
|
|
||||||
|
return testinfo(exitcode=exitcode, execcode=execcode,
|
||||||
|
output=output, linkargs=linkargs,
|
||||||
|
skip_test_expected=skip_test_expected)
|
105
TPfutures/MiniC-futures/test_futures.py
Executable file
105
TPfutures/MiniC-futures/test_futures.py
Executable file
@ -0,0 +1,105 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import pytest
|
||||||
|
import glob
|
||||||
|
import subprocess
|
||||||
|
import re
|
||||||
|
from test_expect_pragma import (
|
||||||
|
TestExpectPragmas, cat, testinfo,
|
||||||
|
env_bool_variable, env_str_variable
|
||||||
|
)
|
||||||
|
|
||||||
|
"""
|
||||||
|
Usage:
|
||||||
|
python3 test_futur.py
|
||||||
|
(or make test)
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
CAP, 2020
|
||||||
|
Unit test infrastructure for testing futures:
|
||||||
|
1) compare the actual output to the expected one (in comments)
|
||||||
|
2) compare the actual output to the one obtained by simulation
|
||||||
|
"""
|
||||||
|
|
||||||
|
DISABLE_TYPECHECK = False
|
||||||
|
TYPECHECK_ONLY = False
|
||||||
|
|
||||||
|
HERE = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
if HERE == os.path.realpath('.'):
|
||||||
|
HERE = '.'
|
||||||
|
TEST_DIR = HERE
|
||||||
|
IMPLEM_DIR = HERE
|
||||||
|
MINIC_FUT = os.path.join(IMPLEM_DIR, 'MiniCC.py')
|
||||||
|
|
||||||
|
ALL_FILES = glob.glob(os.path.join(TEST_DIR, 'tests/**/[a-zA-Z]*.c'),
|
||||||
|
recursive=True)
|
||||||
|
|
||||||
|
GCC = 'gcc'
|
||||||
|
|
||||||
|
if 'TEST_FILES' in os.environ:
|
||||||
|
ALL_FILES = glob.glob(os.environ['TEST_FILES'], recursive=True)
|
||||||
|
|
||||||
|
|
||||||
|
class TestFuture(TestExpectPragmas):
|
||||||
|
|
||||||
|
# Not in test_expect_pragma to get assertion rewritting
|
||||||
|
def assert_equal(self, actual, expected):
|
||||||
|
if TYPECHECK_ONLY and expected.exitcode == 0:
|
||||||
|
# Compiler does not fail => no output expected
|
||||||
|
assert actual.output == "", \
|
||||||
|
("Compiler unexpectedly generated some"
|
||||||
|
"output with --disable-codegen")
|
||||||
|
assert actual.exitcode == 0, \
|
||||||
|
"Compiler unexpectedly failed with --disable-codegen"
|
||||||
|
return
|
||||||
|
if DISABLE_TYPECHECK and expected.exitcode != 0:
|
||||||
|
# Test should fail at typecheck, and we don't do
|
||||||
|
# typechecking => nothing to check.
|
||||||
|
pytest.skip("Test that doesn't typecheck with --disable-typecheck")
|
||||||
|
if expected.output is not None and actual.output is not None:
|
||||||
|
assert actual.output == expected.output, \
|
||||||
|
"Output of the program is incorrect."
|
||||||
|
assert actual.exitcode == expected.exitcode, \
|
||||||
|
"Exit code of the compiler is incorrect"
|
||||||
|
assert actual.execcode == expected.execcode, \
|
||||||
|
"Exit code of the execution is incorrect"
|
||||||
|
|
||||||
|
def c2c(self, file):
|
||||||
|
return self.run_command(['python3', MINIC_FUT, file])
|
||||||
|
|
||||||
|
def compile_with_gcc(self, file, output_name):
|
||||||
|
print("Compiling with GCC...")
|
||||||
|
result = self.run_command(
|
||||||
|
[GCC, '-Iinclude', '-Ilib', '-x', 'c', file, "lib/futurelib.c",
|
||||||
|
'--output=' + output_name, '-lpthread'])
|
||||||
|
print(result.output)
|
||||||
|
print("Compiling with GCC... DONE")
|
||||||
|
return result
|
||||||
|
|
||||||
|
def compile_and_run(self, file):
|
||||||
|
basename, _ = os.path.splitext(file)
|
||||||
|
rw_name = basename + '.cfut'
|
||||||
|
exec_name = basename + '.out'
|
||||||
|
print("File: " + rw_name)
|
||||||
|
resgcc = self.compile_with_gcc(rw_name, exec_name)
|
||||||
|
if resgcc.exitcode != 0:
|
||||||
|
return resgcc._replace(exitcode=1, output=None)
|
||||||
|
res2 = self.run_command(exec_name, scope="runtime")
|
||||||
|
return res2
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('filename', ALL_FILES)
|
||||||
|
def test_future(self, filename):
|
||||||
|
expect = self.get_expect(filename)
|
||||||
|
c2csuccess = self.c2c(filename)
|
||||||
|
if c2csuccess.exitcode == 0:
|
||||||
|
actual = self.compile_and_run(filename)
|
||||||
|
else:
|
||||||
|
actual = c2csuccess
|
||||||
|
self.assert_equal(actual, expect)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
pytest.main(sys.argv)
|
38
TPfutures/MiniC-futures/tests/provided/bad_type_fut1.c
Normal file
38
TPfutures/MiniC-futures/tests/provided/bad_type_fut1.c
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include "compat.h"
|
||||||
|
|
||||||
|
// Call future
|
||||||
|
int slow(int x)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
i=0;
|
||||||
|
while (i<1000) { i=i+1 ; x=2*i+x;}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int summ(int x)
|
||||||
|
{
|
||||||
|
int ret,i;
|
||||||
|
if (x == 1)
|
||||||
|
ret=1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = x + summ(x - 1);
|
||||||
|
i=0;
|
||||||
|
while (i<100) { i=i+1 ; x=slow(2);}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
|
||||||
|
val=Async(summ,1);
|
||||||
|
println_int(val);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXITCODE 2
|
||||||
|
// EXPECTED
|
||||||
|
// In function main: Line 29 col 4: type mismatch for val: integer and futinteger
|
||||||
|
|
20
TPfutures/MiniC-futures/tests/provided/test_fut0.c
Normal file
20
TPfutures/MiniC-futures/tests/provided/test_fut0.c
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include "compat.h"
|
||||||
|
|
||||||
|
// Call future
|
||||||
|
|
||||||
|
int functi(int x){
|
||||||
|
int y;
|
||||||
|
y=x;
|
||||||
|
y = 42;
|
||||||
|
println_int(0);
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
futint fval;
|
||||||
|
fval = Async(functi,123);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECTED
|
||||||
|
// 0
|
22
TPfutures/MiniC-futures/tests/provided/test_fut1.c
Normal file
22
TPfutures/MiniC-futures/tests/provided/test_fut1.c
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "compat.h"
|
||||||
|
|
||||||
|
// Call future
|
||||||
|
|
||||||
|
int functi(int x){
|
||||||
|
int y;
|
||||||
|
y=x;
|
||||||
|
y = 42;
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
futint fval;
|
||||||
|
int val;
|
||||||
|
fval = Async(functi,123);
|
||||||
|
val = Get(fval);
|
||||||
|
println_int(val);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECTED
|
||||||
|
// 42
|
41
TPfutures/MiniC-futures/tests/provided/test_fut2.c
Normal file
41
TPfutures/MiniC-futures/tests/provided/test_fut2.c
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "compat.h"
|
||||||
|
|
||||||
|
// Call future
|
||||||
|
|
||||||
|
int summ(int x)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
if (x == 1)
|
||||||
|
ret=1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret=x + summ(x - 1);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int useFuture(futint f)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
x=Get(f);
|
||||||
|
return x+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int val,x;
|
||||||
|
futint f,g;
|
||||||
|
|
||||||
|
f=Async(summ,15);
|
||||||
|
g=Async(summ,16);
|
||||||
|
|
||||||
|
val=Get(f)+Get(g)+useFuture(g);
|
||||||
|
println_int(val);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// EXPECTED
|
||||||
|
// 393
|
56
TPfutures/MiniC-futures/tests/provided/test_fut4.c
Normal file
56
TPfutures/MiniC-futures/tests/provided/test_fut4.c
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include "compat.h"
|
||||||
|
|
||||||
|
// Call future
|
||||||
|
|
||||||
|
int slow(int x)
|
||||||
|
{
|
||||||
|
int i,t;
|
||||||
|
i=0;
|
||||||
|
t=0;
|
||||||
|
while (i<x*1000) { i=i+1 ; t=t+2*i+x;}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
int summ(int x)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
if (x == 1)
|
||||||
|
ret=1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = x + summ(x - 1);
|
||||||
|
i=0;
|
||||||
|
while (i<100) { i=i+1 ; x=slow(20);}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int summandprint(int x)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
ret=summ(x);
|
||||||
|
println_int(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
futint f,g;
|
||||||
|
|
||||||
|
f=Async(summandprint,500);
|
||||||
|
g=Async(summandprint,2);
|
||||||
|
|
||||||
|
val=Get(f)+Get(g);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// EXPECTED
|
||||||
|
// 3
|
||||||
|
// 125250
|
BIN
TPfutures/tpfutures.pdf
Normal file
BIN
TPfutures/tpfutures.pdf
Normal file
Binary file not shown.
BIN
course/cap_cours08_func_codegen.pdf
Normal file
BIN
course/cap_cours08_func_codegen.pdf
Normal file
Binary file not shown.
BIN
course/cap_cours09_func_semantics.pdf
Normal file
BIN
course/cap_cours09_func_semantics.pdf
Normal file
Binary file not shown.
BIN
course/cap_cours10_parallelism.pdf
Normal file
BIN
course/cap_cours10_parallelism.pdf
Normal file
Binary file not shown.
BIN
course/cap_cours11_verified.pdf
Normal file
BIN
course/cap_cours11_verified.pdf
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user