1 package de.yasc.example.petrinet;
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.InputStreamReader;
7 import java.util.ArrayList;
9 public final class PetrinetParser implements AutoCloseable {
11 private final BufferedReader reader;
13 public PetrinetParser(InputStream stream) {
14 reader = new BufferedReader(new InputStreamReader(stream));
17 private static class Line {
20 PLACES, TRANSITION, MARKING, COMMENT, UNKNOWN;
28 private Integer parsePositiveInt(String token) throws IOException {
30 var val = Integer.valueOf(token);
32 throw new IOException("invalid input - '" + token + "' is not positive");
35 } catch (NumberFormatException ex) {
36 throw new IOException("invalid input - '" + token + "' is not an integer");
40 private void parsePlaces(String tokens[]) throws IOException {
41 if (tokens.length != 2) {
42 throw new IOException("invalid input - syntax of places is 'p <#n>'");
44 val0 = parsePositiveInt(tokens[1]);
47 private void parseTransition(String tokens[]) throws IOException {
48 if (tokens.length < 4) {
49 throw new IOException("invalid input - syntax of transition is 't <pre_1> ... <pre_m> / <post_1> ... <post_n>'");
51 var vals = new ArrayList<>();
53 for (; i < tokens.length; i++) {
54 if (tokens[i].equals("/")) {
58 vals.add(parsePositiveInt(tokens[i]));
60 val1 = vals.toArray(new Integer[0]);
61 if (i == tokens.length) {
62 throw new IOException("invalid input - transition has no postset");
64 if (val1.length == 0) {
65 throw new IOException("invalid input - transition has no preset");
68 for (; i < tokens.length; i++) {
69 vals.add(parsePositiveInt(tokens[i]));
71 val2 = vals.toArray(new Integer[0]);
74 private void parseMarking(String tokens[]) throws IOException {
75 if (tokens.length < 2) {
76 throw new IOException("invalid input - syntax of marking is 'm <place_1> ... <place_n>");
78 var vals = new ArrayList<>();
80 for (; i < tokens.length; i++) {
81 vals.add(parsePositiveInt(tokens[i]));
83 val1 = vals.toArray(new Integer[0]);
86 Line(String line) throws IOException {
90 var tokens = line.split("\\s");
91 assert tokens.length > 0;
98 type = Type.TRANSITION;
99 parseTransition(tokens);
103 parseMarking(tokens);
115 public Petrinet read() throws IOException {
116 Petrinet result = null;
120 while ((input = reader.readLine()) != null) {
123 var parsedLine = new Line(input);
124 switch (parsedLine.type) {
127 if (result == null) {
128 result = new Petrinet(parsedLine.val0);
130 throw new IOException("places command must occur once");
135 throw new IOException("the first command must be 'p' to define the places");
136 result.addTransistion(parsedLine.val1, parsedLine.val2);
140 throw new IOException("the first command must be 'p' to define the places");
141 result.addMarking(parsedLine.val1);
144 throw new IOException("unknown command");
146 } catch (IndexOutOfBoundsException ex) {
147 throw new IOException(String.format("a place with the specified index does not exist (line %d)", line), ex);
148 } catch (IOException ex) {
149 throw new IOException(ex.getMessage() + String.format(" (line %d)", line), ex);
157 public void close() throws IOException {