Skip to content

Commit 429856a

Browse files
committed
Create Example.java
1 parent 8211f10 commit 429856a

File tree

2 files changed

+478
-8
lines changed

2 files changed

+478
-8
lines changed

README.md

Lines changed: 243 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,9 @@ uściśleń przez kontekst, wówczas należy używać instancji utworzonej przez
1414

1515
Interfejs [Interpreter](https://github.com/koder95/Interpreter/blob/master/src/main/java/pl/koder95/interpreter/Interpreter.java) dostarcza nie tylko
1616
[metodę interpretującą odczytywane wartości](https://github.com/koder95/Interpreter/blob/b3f9b37f580d7580785ac4515601e07ce9b38d85/src/main/java/pl/koder95/interpreter/Interpreter.java#L38),
17-
ale również implementacje interfejsów [parsera](https://github.com/koder95/Interpreter/blob/master/src/main/java/pl/koder95/interpreter/Parser.java),
18-
[tokenizera](https://github.com/koder95/Interpreter/blob/master/src/main/java/pl/koder95/interpreter/Tokenizer.java)
19-
oraz [fabryki skanerów](https://github.com/koder95/Interpreter/blob/master/src/main/java/pl/koder95/interpreter/ScannerFactory.java),
20-
które wykorzystywane są podczas budowania drzewa abstrakcyjnej syntaktyki za pomocą metod
21-
[create(java.lang.Readable)](https://github.com/koder95/Interpreter/blob/b3f9b37f580d7580785ac4515601e07ce9b38d85/src/main/java/pl/koder95/interpreter/ScannerFactory.java#L19),
22-
[buildAbstractSyntaxTree(java.util.Queue)](https://github.com/koder95/Interpreter/blob/b3f9b37f580d7580785ac4515601e07ce9b38d85/src/main/java/pl/koder95/interpreter/Parser.java#L17)
23-
oraz [enqueue()](https://github.com/koder95/Interpreter/blob/b3f9b37f580d7580785ac4515601e07ce9b38d85/src/main/java/pl/koder95/interpreter/Tokenizer.java#L54).
17+
ale również implementacje interfejsu [parsera](https://github.com/koder95/Interpreter/blob/master/src/main/java/pl/koder95/interpreter/Parser.java),
18+
który wykorzystywany jest do budowania drzewa abstrakcyjnej syntaktyki za pomocą metody
19+
[buildAbstractSyntaxTree(java.util.Queue)](https://github.com/koder95/Interpreter/blob/2d2197598c8597dac693b7520f52d9bac62c9ade/src/main/java/pl/koder95/interpreter/Parser.java#L23).
2420

2521
## Zależność Maven
2622
```xml
@@ -29,4 +25,243 @@ oraz [enqueue()](https://github.com/koder95/Interpreter/blob/b3f9b37f580d7580785
2925
<artifactId>Interpreter</artifactId>
3026
<version>1.0-SNAPSHOT</version>
3127
</dependency>
32-
```
28+
```
29+
30+
## Przykład
31+
```java
32+
package pl.koder95.interpreter;
33+
34+
import java.io.StringReader;
35+
import java.util.*;
36+
37+
/**
38+
* Klasa zawierająca przykładową implementację interpretera.
39+
* Zaimplementowany język jest kontekstowy i określa sortowanie ciągów znaków za pomocą instrukcji
40+
* {@code ORDER BY ASC} lub {@code ORDER BY DSC}, albo {@code ORDER BY REV}.
41+
* Dla pewnego porządku: język nazywa się {@code SortExaL} od
42+
* ang. <i><b>Sort</b>ing <b>Exa</b>mple <b>L</b>anguage</i> (przykładowy język sortowania).
43+
*/
44+
public final class Example {
45+
46+
private Example() {}
47+
48+
/**
49+
* Metoda interpretująca źródło znaków i wprowadzone linie.
50+
* @param readable źródło znaków do zinterpretowania
51+
* @param lines tablica linii umieszczonych w kontekście przed procesem interpretacji
52+
* @return lista linii posortowanych zgodnie z instrukcjami
53+
*/
54+
public static List<String> interpret(Readable readable, String... lines) {
55+
// Poniższy przykład pokazuje sposób korzystania z interpretera.
56+
// Pierwszym krokiem jest utworzenie obiektu klienta:
57+
ExampleClient client = new ExampleClient();
58+
// Należy stworzyć najpierw instancję kontekstu, który będzie wykorzystywany przez interpreter:
59+
ExampleContext context = new ExampleContext();
60+
if (lines.length > 0) {// – sprawdzanie, czy są jakieś linie we wprowadzonej tablicy
61+
context.lines.addAll(List.of(lines)); // – linie dodawane są do kontekstu
62+
}
63+
// Aby utworzyć nową instancję interpretera, należy to zrobić za pośrednictwem klienta:
64+
ExampleInterpreter interpreter = client.newInterpreter(context);
65+
// Interpreter dokonuje interpretacji źródła znaków i zwraca wynik w postaci listy linii:
66+
return interpreter.interpret(readable);
67+
}
68+
69+
public static void main(String[] args) {
70+
// Przykładowe instrukcje:
71+
String expressions = """
72+
B
73+
D
74+
C
75+
ORDER BY DSC
76+
A
77+
ORDER BY REV
78+
E
79+
ORDER BY REV
80+
ORDER BY REV
81+
F
82+
""";
83+
StringReader readable = new StringReader(expressions);
84+
// Interpreter dokonuje interpretacji i zwraca wynik w postaci listy linii:
85+
List<String> lines = args.length > 0? interpret(readable, String.join(" ", args)) : interpret(readable);
86+
// Drukowanie wyników interpretacji:
87+
System.out.println(lines); // Spodziewany print (jeśli nie było argumentów): [A, B, C, D, E, F]
88+
}
89+
90+
/*
91+
IMPLEMENTACJE
92+
=============
93+
* ExampleContext – implementuje przykładowy kontekst dla języka kontekstowego
94+
* Line – implementuje wyrażenie nieterminalne reprezentujące linię tekstu
95+
* OrderByType – definiuje typy sposobów porządkowania linii tekstu
96+
* Sort – implementuje wyrażenie terminalne, które zwraca posortowane linie według podanego sposobu
97+
* Add – implementuje wyrażenie terminalne, które dodaje do kontekstu linię tekstu
98+
* Instructions – implementuje wyrażenie terminalne, które zawiera listę innych wyrażeń terminalnych
99+
* LineTokenizer – dokonuje tokenizacji dzieląc źródło znaków na linie
100+
* ExampleParser – implementuje parser, który tworzy AST (zwraca Instructions)
101+
* ExampleInterpreter – implementuje interpreter przez określenie statycznego parsera i zmiennego kontekstu
102+
* ExampleClient – implementuje klienta tworzącego interpreter
103+
104+
LineTokenizer pobiera znaki i przekształca je w linie (Line).
105+
Parser (ExampleParser) analizuje linie i określa ich znaczenie.
106+
Linie są przekształcane przez parser na Add albo Sort, które dodawane są do listy instrukcji (Instructions).
107+
Interpreter (ExampleInterpreter) dokonuje interpretacji instrukcji i zwraca listę posortowanych linii.
108+
Klient zajmuje się utworzeniem interpretera, w zależności od kontekstu (w tym miejscu jest on ignorowany).
109+
*/
110+
private static class ExampleContext implements Context {
111+
private final List<String> lines = new LinkedList<>();
112+
}
113+
114+
private record Line(String content) implements NonTerminalExpression<String> {
115+
@Override
116+
public String getObject() {
117+
return content;
118+
}
119+
}
120+
121+
private enum OrderByType {
122+
ASC, DSC, REV
123+
}
124+
125+
private record Sort(OrderByType orderBy) implements TerminalExpression<ExampleContext, List<String>> {
126+
127+
@Override
128+
public List<String> interpret(ExampleContext context) {
129+
if (orderBy == OrderByType.ASC) context.lines.sort(Comparator.naturalOrder());
130+
else if (orderBy == OrderByType.DSC) context.lines.sort(Comparator.reverseOrder());
131+
else if (orderBy == OrderByType.REV) Collections.reverse(context.lines);
132+
List<String> ordered = new ArrayList<>(context.lines);
133+
context.lines.clear();
134+
return ordered;
135+
}
136+
137+
@Override
138+
public String asString() {
139+
return "ORDER BY " + orderBy.name();
140+
}
141+
}
142+
143+
private record Add(Line line) implements TerminalExpression<ExampleContext, List<String>> {
144+
@Override
145+
public List<String> interpret(ExampleContext context) {
146+
if (line != null) context.lines.add(line.content);
147+
return context.lines;
148+
}
149+
150+
@Override
151+
public String asString() {
152+
return line == null? "null" : line.content();
153+
}
154+
}
155+
156+
private record Instructions(List<TerminalExpression<ExampleContext, List<String>>> terminalExpressionList)
157+
implements TerminalExpression<ExampleContext, List<String>> {
158+
@Override
159+
public List<String> interpret(ExampleContext context) {
160+
for (TerminalExpression<ExampleContext, List<String>> expr : terminalExpressionList) {
161+
List<String> interpreted = expr.interpret(context);
162+
if (expr instanceof Sort) {
163+
context.lines.addAll(interpreted);
164+
}
165+
}
166+
return context.lines;
167+
}
168+
169+
@Override
170+
public String asString() {
171+
return "INSTRUCTIONS";
172+
}
173+
}
174+
175+
private static final class LinesTokenizer extends Tokenizer {
176+
private final Queue<Line> lineQueue = new LinkedList<>();
177+
private Scanner scanner = null;
178+
179+
@Override
180+
public Line next() {
181+
while (scanner != null && scanner.hasNextLine()) {
182+
String content = scanner.nextLine();
183+
lineQueue.add(new Line(content));
184+
}
185+
return lineQueue.poll();
186+
}
187+
188+
@Override
189+
public boolean hasNext() {
190+
return (scanner != null && scanner.hasNext()) || !lineQueue.isEmpty();
191+
}
192+
193+
@Override
194+
public void setSource(Readable source) {
195+
super.setSource(source);
196+
scanner = new Scanner(source);
197+
}
198+
}
199+
200+
private static final class ExampleParser implements Parser<ExampleContext, List<String>> {
201+
public static final Tokenizer TOKENIZER = new LinesTokenizer();
202+
203+
@Override
204+
public Tokenizer getTokenizer() {
205+
return TOKENIZER;
206+
}
207+
208+
@Override
209+
public TerminalExpression<ExampleContext, List<String>> buildAbstractSyntaxTree(Queue<NonTerminalExpression<?>> tokens) {
210+
List<TerminalExpression<ExampleContext, List<String>>> terminalExpressionList = new LinkedList<>();
211+
while (!tokens.isEmpty()) {
212+
NonTerminalExpression<?> token = tokens.poll();
213+
if (token instanceof Line line) {
214+
String content = line.content();
215+
String tag = "ORDER BY";
216+
if (content.startsWith(tag)) {
217+
Sort sorting = recognizeSort(content.substring(tag.length()).strip());
218+
terminalExpressionList.add(sorting);
219+
} else {
220+
terminalExpressionList.add(new Add(line));
221+
}
222+
} else {
223+
terminalExpressionList.add(new Add(new Line(token.asString())));
224+
}
225+
}
226+
return new Instructions(terminalExpressionList);
227+
}
228+
229+
private static Sort recognizeSort(String type) {
230+
Sort sorting;
231+
if (type.equals(OrderByType.ASC.name())) {
232+
sorting = new Sort(OrderByType.ASC);
233+
} else if (type.equals(OrderByType.DSC.name())) {
234+
sorting = new Sort(OrderByType.DSC);
235+
} else if (type.equals(OrderByType.REV.name())) {
236+
sorting = new Sort(OrderByType.REV);
237+
} else if (type.isBlank()) {
238+
sorting = new Sort(null);
239+
} else {
240+
throw new SyntaxException("Unknown ordering type");
241+
}
242+
return sorting;
243+
}
244+
}
245+
246+
private record ExampleInterpreter(ExampleContext context) implements Interpreter<ExampleContext, List<String>> {
247+
public static final ExampleParser PARSER = new ExampleParser();
248+
249+
@Override
250+
public ExampleContext getContext() {
251+
return context;
252+
}
253+
254+
@Override
255+
public ExampleParser getParser() {
256+
return PARSER;
257+
}
258+
}
259+
260+
private static final class ExampleClient implements Client<ExampleContext, List<String>, ExampleInterpreter> {
261+
@Override
262+
public ExampleInterpreter newInterpreter(ExampleContext context) {
263+
return new ExampleInterpreter(context);
264+
}
265+
}
266+
}
267+
```

0 commit comments

Comments
 (0)