Skip to content

Method: Scanner(int)

1: package de.fhdw.wtf.dsl.scanner.common;
2:
3: import java.util.List;
4:
5: import de.fhdw.wtf.common.stream.ScannerInputStream;
6: import de.fhdw.wtf.common.stream.TokenStream;
7: import de.fhdw.wtf.common.token.EndToken;
8: import de.fhdw.wtf.common.token.Position;
9:
10: /**
11: * <h1>Scanner</h1> The {@link Scanner} can be used to transform <i>WTF-code</i> in the form of a
12: * {@link ScannerInputStream} into the corresponding {@link TokenStream}.
13: *
14: * @author hf(w|i|t)411
15: */
16: public abstract class Scanner {
17:         
18:         /**
19:          * Width of the tabulator.
20:          */
21:         private final int tabulatorWidth;
22:         
23:         /**
24:          * If this character appears in the input stream, the position will be adjusted to show a new line.
25:          */
26:         private static final char LINE_FEED = '\n';
27:         
28:         /**
29:          * If this character appears in the input stream, the tabulatorWidth will be add to the position.
30:          */
31:         private static final char TAB = '\t';
32:         
33:         /**
34:          * Constructor for {@link Scanner}.
35:          *
36:          * @param tabulatorWidth
37:          * Width of TAB (editor-setting) for calculation of token column positions
38:          */
39:         protected Scanner(final int tabulatorWidth) {
40:                 this.tabulatorWidth = tabulatorWidth;
41:         }
42:         
43:         /**
44:          * Returns the delta-function of the Scanner-automata by defining all transitions ({@link Delta}s).
45:          *
46:          * @return delta-function
47:          */
48:         protected abstract List<Delta> getDeltas();
49:         
50:         /**
51:          * Returns the first {@link ScannerState}.
52:          *
53:          * @return first {@link ScannerState}
54:          */
55:         protected abstract ScannerState getStartState();
56:         
57:         /**
58:          * Returns the {@link ScannerState} witch will be used if no {@link Delta} has matched at
59:          * {@link #step(ScannerState, Character, Position, TokenStream)} e.g. an invalid state.
60:          *
61:          * @param position
62:          * position
63:          * @return Default-State
64:          */
65:         protected abstract ScannerState getDefaultState(Position position);
66:         
67:         /**
68:          * Reads the given {@link ScannerInputStream}, scans regular language tokens and writes the corresponding Tokens
69:          * into the given {@link TokenStream}.
70:          *
71:          * @param inputStream
72:          * where characters are read from
73:          * @param outputStream
74:          * where created Tokens are added
75:          */
76:         public void scan(final ScannerInputStream inputStream, final TokenStream outputStream) {
77:                 ScannerState state = this.getStartState();
78:                 final String filePath = "";
79:                 // TODO Fix filePath when imports are allowed in grammar (Bug #769)
80:                 int lineNumber = 1;
81:                 int positionInFile = 0;
82:                 int positionInLine = 1;
83:                 
84:                 while (inputStream.hasNext()) {
85:                         final char current = inputStream.next();
86:                         final Position position = Position.create(filePath, lineNumber, positionInLine, positionInFile);
87:                         state = this.step(state, current, position, outputStream);
88:                         state.process(current, outputStream, position);
89:                         
90:                         if (current == TAB) {
91:                                 final int spacesToInsert = this.tabulatorWidth - ((positionInLine - 1) % this.tabulatorWidth);
92:                                 positionInLine += spacesToInsert;
93:                         } else {
94:                                 positionInLine++;
95:                         }
96:                         
97:                         positionInFile++;
98:                         
99:                         // Zeilenumbruch
100:                         if (current == LINE_FEED) {
101:                                 lineNumber++;
102:                                 positionInLine = 1;
103:                         }
104:                 }
105:                 state.finish(outputStream);
106:                 outputStream.add(EndToken.create(Position.create(filePath, lineNumber, positionInLine, positionInFile)));
107:         }
108:         
109:         /**
110:          * Returns the next {@link ScannerState} and finishes the last {@link ScannerState}.
111:          *
112:          * @param currentState
113:          * the current {@link ScannerState}
114:          * @param c
115:          * the current input {@link Character}
116:          * @param position
117:          * the current {@link Position}
118:          * @param outputStream
119:          * {@link TokenStream}
120:          * @return the next {@link ScannerState}
121:          */
122:         private ScannerState step(final ScannerState currentState,
123:                         final Character c,
124:                         final Position position,
125:                         final TokenStream outputStream) {
126:                 for (final Delta d : this.getDeltas()) {
127:                         if (d.match(currentState, c)) {
128:                                 final ScannerState nextState = d.getNextScannerState(position, currentState);
129:                                 if (!nextState.equals(currentState)) {
130:                                         currentState.finish(outputStream);
131:                                 }
132:                                 return nextState;
133:                         }
134:                 }
135:                 currentState.finish(outputStream);
136:                 return this.getDefaultState(position);
137:         }
138: }