From 59cf66506f28a9bc7fef42ec0b90a0eabbfa2097 Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Tue, 27 Jun 2017 13:27:56 +0200 Subject: [PATCH] move common code to __init__ --- src/JobShopParser/__init__.py | 90 ++++++++++++++++++++++++++++ src/JobShopParser/common.py | 90 ---------------------------- src/JobShopParser/jobshop1_parser.py | 5 +- src/JobShopParser/jobshop2_parser.py | 6 +- 4 files changed, 95 insertions(+), 96 deletions(-) delete mode 100644 src/JobShopParser/common.py diff --git a/src/JobShopParser/__init__.py b/src/JobShopParser/__init__.py index e69de29..51df1c2 100644 --- a/src/JobShopParser/__init__.py +++ b/src/JobShopParser/__init__.py @@ -0,0 +1,90 @@ +from typing import List, Tuple, Sequence, Optional, Union +import arpeggio + +grammar = """ + # starting point for jobshop1 input file + job_shop1 = skip_preface + # eat away lines of preface, until first problem_instance is encountered; then the list of instances start + skip_preface = (!problem_instance r"[^\n]+" skip_preface) / (eol skip_preface) / instance_list + instance_list = problem_instance (sep_line trim_ws eol problem_instance eol?)* eof_sep + problem_instance = trim_ws "instance" ' ' instance_name trim_ws eol trim_ws eol sep_line description eol problem_data + description = r"[^\n]*" + instance_name = r"\w+" + sep_line = trim_ws plus_line trim_ws eol + # lines out of multiple + signs + plus_line = r"\+\+\++" + # EOF is a builtin rule matching end of file + eof_sep = trim_ws plus_line " EOF " plus_line trim_ws eol* EOF + # entry point for jobshop2 input files + job_shop2 = problem_data EOF + problem_data = trim_ws num_jobs ' ' num_machines eol job_data+ + # used for skipping arbitrary number of non-breaking whitespace + trim_ws = r'[ \t]*' + # git may change line-endings on windows, so we have to match on both + eol = "\n" / "\r\n" + nonneg_num = r'\d+' + num_jobs = nonneg_num + num_machines = nonneg_num + machine = nonneg_num + duration = nonneg_num + # task data for 1 job + job_data = ' '* machine ' '+ duration (' '+ machine ' '+ duration)* trim_ws eol + """ + +class ParseError(Exception): + """To be thrown when parsing goes wrong""" + + def __init__(self, message: str) -> None: + self.message = message + +class JobShopProblem: + + def __init__(self, jobs: int, machines: int, problem_data: List[List[Tuple[int, int]]], name: str = 'unnamed', description: str = '') -> None: + self.description = description + self.name = name + self.problem_data = problem_data + self.machines = machines + self.jobs = jobs + + def __str__(self) -> str: + return self.name + +class JobShopVisitor(arpeggio.PTNodeVisitor): + """contains visitor functions needed for both jobshop1 (list of instances) + and jobshop2 (single instance without name & description) input data""" + + def visit_nonneg_num(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int: + if self.debug: + print("Converting non-negative integer", node.value) + return int(node.value) + + def visit_machine(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int: + return int(node.value) + + def visit_duration(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int: + return int(node.value) + + def visit_num_machines(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int: + return int(node.value) + + def visit_num_jobs(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int: + return int(node.value) + + def visit_job_data(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> List[Tuple[int, int]]: + if self.debug: + print("Job data:\nnode:", type(node), "children:", children) + job_numbers = list(filter(lambda x: type(x) is int, children)) + # job data needs to consist out of pairs of numbers + if len(job_numbers) % 2 ==1: + raise ParseError("Odd number of numbers in job data") + # returns list of (duration, machine) tuples + return list(zip(job_numbers[1::2], job_numbers[0::2])) + + def visit_problem_data(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> JobShopProblem: + if self.debug: + print("problem_data\nchildren:", children) + cleaned_data = list(filter(lambda x: type(x) is not str, children)) + problem_data: List[List[Tuple(int, int)]] = [ cleaned_data[i] for i in range(2, len(cleaned_data))] + return JobShopProblem(children[0], children[1], problem_data) + + diff --git a/src/JobShopParser/common.py b/src/JobShopParser/common.py deleted file mode 100644 index 51df1c2..0000000 --- a/src/JobShopParser/common.py +++ /dev/null @@ -1,90 +0,0 @@ -from typing import List, Tuple, Sequence, Optional, Union -import arpeggio - -grammar = """ - # starting point for jobshop1 input file - job_shop1 = skip_preface - # eat away lines of preface, until first problem_instance is encountered; then the list of instances start - skip_preface = (!problem_instance r"[^\n]+" skip_preface) / (eol skip_preface) / instance_list - instance_list = problem_instance (sep_line trim_ws eol problem_instance eol?)* eof_sep - problem_instance = trim_ws "instance" ' ' instance_name trim_ws eol trim_ws eol sep_line description eol problem_data - description = r"[^\n]*" - instance_name = r"\w+" - sep_line = trim_ws plus_line trim_ws eol - # lines out of multiple + signs - plus_line = r"\+\+\++" - # EOF is a builtin rule matching end of file - eof_sep = trim_ws plus_line " EOF " plus_line trim_ws eol* EOF - # entry point for jobshop2 input files - job_shop2 = problem_data EOF - problem_data = trim_ws num_jobs ' ' num_machines eol job_data+ - # used for skipping arbitrary number of non-breaking whitespace - trim_ws = r'[ \t]*' - # git may change line-endings on windows, so we have to match on both - eol = "\n" / "\r\n" - nonneg_num = r'\d+' - num_jobs = nonneg_num - num_machines = nonneg_num - machine = nonneg_num - duration = nonneg_num - # task data for 1 job - job_data = ' '* machine ' '+ duration (' '+ machine ' '+ duration)* trim_ws eol - """ - -class ParseError(Exception): - """To be thrown when parsing goes wrong""" - - def __init__(self, message: str) -> None: - self.message = message - -class JobShopProblem: - - def __init__(self, jobs: int, machines: int, problem_data: List[List[Tuple[int, int]]], name: str = 'unnamed', description: str = '') -> None: - self.description = description - self.name = name - self.problem_data = problem_data - self.machines = machines - self.jobs = jobs - - def __str__(self) -> str: - return self.name - -class JobShopVisitor(arpeggio.PTNodeVisitor): - """contains visitor functions needed for both jobshop1 (list of instances) - and jobshop2 (single instance without name & description) input data""" - - def visit_nonneg_num(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int: - if self.debug: - print("Converting non-negative integer", node.value) - return int(node.value) - - def visit_machine(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int: - return int(node.value) - - def visit_duration(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int: - return int(node.value) - - def visit_num_machines(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int: - return int(node.value) - - def visit_num_jobs(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int: - return int(node.value) - - def visit_job_data(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> List[Tuple[int, int]]: - if self.debug: - print("Job data:\nnode:", type(node), "children:", children) - job_numbers = list(filter(lambda x: type(x) is int, children)) - # job data needs to consist out of pairs of numbers - if len(job_numbers) % 2 ==1: - raise ParseError("Odd number of numbers in job data") - # returns list of (duration, machine) tuples - return list(zip(job_numbers[1::2], job_numbers[0::2])) - - def visit_problem_data(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> JobShopProblem: - if self.debug: - print("problem_data\nchildren:", children) - cleaned_data = list(filter(lambda x: type(x) is not str, children)) - problem_data: List[List[Tuple(int, int)]] = [ cleaned_data[i] for i in range(2, len(cleaned_data))] - return JobShopProblem(children[0], children[1], problem_data) - - diff --git a/src/JobShopParser/jobshop1_parser.py b/src/JobShopParser/jobshop1_parser.py index 0d80899..31f9c3c 100644 --- a/src/JobShopParser/jobshop1_parser.py +++ b/src/JobShopParser/jobshop1_parser.py @@ -2,8 +2,7 @@ from arpeggio.cleanpeg import ParserPEG from typing import List, Tuple, Sequence, Optional, Union import arpeggio -from common import grammar, ParseError, JobShopProblem, JobShopVisitor -#from . import JobShopProblem +from . import grammar, ParseError, JobShopProblem, JobShopVisitor class JobShop1Visitor(JobShopVisitor): """instanciated for semantic analysis of parse_tree""" @@ -45,7 +44,7 @@ def parse_jobshop1_file(filename: Union[str, bytes]) -> List[JobShopProblem]: def main(): - print(parse_jobshop1_file("inputdata/jobshop1.txt")) + print(parse_jobshop1_file("../inputdata/jobshop1.txt")) parser = ParserPEG(grammar, "job_shop1", skipws=False) diff --git a/src/JobShopParser/jobshop2_parser.py b/src/JobShopParser/jobshop2_parser.py index c7fbd0b..dc49898 100644 --- a/src/JobShopParser/jobshop2_parser.py +++ b/src/JobShopParser/jobshop2_parser.py @@ -2,7 +2,7 @@ import arpeggio from arpeggio.cleanpeg import ParserPEG from typing import List, Tuple, Sequence, Optional, Union -from common import grammar, JobShopVisitor, JobShopProblem +from . import grammar, JobShopVisitor, JobShopProblem class JobShop2Visitor(JobShopVisitor): pass @@ -17,9 +17,9 @@ def parse_jobshop2_file(filename: Union[str, bytes]) -> JobShopProblem: return arpeggio.visit_parse_tree(parse_tree, JobShop2Visitor()) def main(): - print(parse_jobshop2_file('./inputdata/jobshop2/ta13').problem_data) + print(type(parse_jobshop2_file('../inputdata/jobshop2/ta13').problem_data)) -parser = ParserPEG(grammar, "problem_data", skipws=False) +parser = ParserPEG(grammar, "job_shop2", skipws=False) if __name__ == "__main__": main()