1 module bf_parser;
2 
3 enum BFTokenEnum
4 {
5     IncPtr = '>',
6     DecPtr = '<',
7     IncVal = '+',
8     DecVal = '-',
9     OutputVal = '.',
10     InputVal = ',',
11     LoopBegin = '[',
12     LoopEnd = ']',
13 
14     ProgrammBegin,
15     ProgrammEnd,
16 }
17 
18 /**
19 represent RepeatedToken as uint
20 [0 .. 24] count
21 [24 .. 32] token
22 */
23 struct RepeatedToken
24 {
25     uint _token;
26     alias _token this;
27 
28     @property BFTokenEnum token() const pure
29     {
30         return cast(BFTokenEnum)(_token >> 24);
31     }
32 
33     @property uint count() const pure
34     {
35         return _token & 0x00_FF_FF_FF;
36     }
37 }
38 
39 RepeatedToken Token(BFTokenEnum token) pure
40 {
41     return cast(RepeatedToken)(token << 24 | 1);
42 }
43 
44 const(RepeatedToken[]) parseBf(const string input) pure
45 {
46     uint pos;
47     RepeatedToken[] result;
48     result.length = input.length + 2;
49     // the maximal number of diffrent tokens is equal to the chars in the input
50     // plus the begin and end token
51 
52     result[0] = Token(BFTokenEnum.ProgrammBegin);
53     uint resultLen = 0;
54 
55     while (pos < input.length)
56     {
57         uint lastToken = (result[resultLen] >> 24);
58         uint thisToken = BFTokenEnum.ProgrammEnd;
59         final switch (input[pos++]) with (BFTokenEnum)
60         {
61         case '>':
62             thisToken = IncPtr;
63             break;
64         case '<':
65             thisToken = DecPtr;
66             break;
67         case '+':
68             thisToken = IncVal;
69             break;
70         case '-':
71             thisToken = DecVal;
72             break;
73         case '.':
74             thisToken = OutputVal;
75             break;
76         case ',':
77             thisToken = InputVal;
78             break;
79         case '[':
80             thisToken = LoopBegin;
81             break;
82         case ']':
83             thisToken = LoopEnd;
84             break;
85         case '\r':
86             pos++;
87             goto case '\n';
88         case '\n':
89             //TODO handle lines and proper position informmation;
90             break;
91         }
92 
93 
94         if (lastToken == thisToken)
95         {
96             result[resultLen]++;
97         }
98         else if (thisToken != BFTokenEnum.ProgrammEnd)
99         {
100             result[++resultLen] = Token(cast(BFTokenEnum)thisToken);
101         }
102 
103     }
104 
105     result[++resultLen] = Token(BFTokenEnum.ProgrammEnd);
106     return result[0 .. resultLen + 1];
107 }