@@ -14,13 +14,9 @@ uściśleń przez kontekst, wówczas należy używać instancji utworzonej przez
14
14
15
15
Interfejs [ Interpreter] ( https://github.com/koder95/Interpreter/blob/master/src/main/java/pl/koder95/interpreter/Interpreter.java ) dostarcza nie tylko
16
16
[ 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 ) .
24
20
25
21
## Zależność Maven
26
22
``` xml
@@ -29,4 +25,243 @@ oraz [enqueue()](https://github.com/koder95/Interpreter/blob/b3f9b37f580d7580785
29
25
<artifactId >Interpreter</artifactId >
30
26
<version >1.0-SNAPSHOT</version >
31
27
</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