Compare commits
No commits in common. "293c52d9677fa6bd2fff098d2ace1fe1a73950f9" and "df9ebe0a3b4304e773d4f8c3a438a3229875c15b" have entirely different histories.
293c52d967
...
df9ebe0a3b
34
PLANNING.md
34
PLANNING.md
@ -103,45 +103,13 @@ _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/).
|
||||||
* Parsing and typechecking functions [TP06a](TP06/tp6a.pdf), code in [MiniC/](MiniC/).
|
* Other possibilities next week.
|
||||||
* 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
BIN
TP06/tp6a.pdf
Binary file not shown.
BIN
TP06/tp6b.pdf
BIN
TP06/tp6b.pdf
Binary file not shown.
15
TPfutures/MiniC-futures/.gitignore
vendored
15
TPfutures/MiniC-futures/.gitignore
vendored
@ -1,15 +0,0 @@
|
|||||||
/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
|
|
@ -1,14 +0,0 @@
|
|||||||
class MiniCRuntimeError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class MiniCInternalError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class MiniCUnsupportedError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class MiniCTypeError(Exception):
|
|
||||||
pass
|
|
@ -1,56 +0,0 @@
|
|||||||
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
|
|
@ -1,164 +0,0 @@
|
|||||||
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)
|
|
||||||
;
|
|
||||||
|
|
@ -1,112 +0,0 @@
|
|||||||
#! /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)
|
|
@ -1,27 +0,0 @@
|
|||||||
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, '&')
|
|
@ -1,17 +0,0 @@
|
|||||||
# 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
|
|
@ -1,25 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
|||||||
#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);
|
|
@ -1,34 +0,0 @@
|
|||||||
#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
|
|
@ -1,77 +0,0 @@
|
|||||||
#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)
|
|
||||||
}
|
|
@ -1,193 +0,0 @@
|
|||||||
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)
|
|
@ -1,105 +0,0 @@
|
|||||||
#! /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)
|
|
@ -1,38 +0,0 @@
|
|||||||
#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
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
|||||||
#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
|
|
@ -1,22 +0,0 @@
|
|||||||
#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
|
|
@ -1,41 +0,0 @@
|
|||||||
#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
|
|
@ -1,56 +0,0 @@
|
|||||||
#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
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user