1 module parser; 2 3 import pry.stream; 4 5 alias Stream = SimpleStream!string; 6 7 bool expr(ref Stream s, ref int val, ref Stream.Error err){ 8 int v; 9 if(!term(s, v, err)){ 10 return false; 11 } 12 if(s.empty){ 13 val = v; 14 return true; 15 } 16 switch(s.front){ 17 case '+': 18 s.popFront(); 19 int v2; 20 if(!expr(s, v2, err)){ 21 return false; 22 } 23 val = v + v2; 24 return true; 25 case '-': 26 s.popFront(); 27 int v2; 28 if(!expr(s, v2, err)){ 29 return false; 30 } 31 val = v - v2; 32 return true; 33 default: 34 val = v; 35 return true; 36 } 37 } 38 39 bool term(ref Stream s, ref int val, ref Stream.Error err){ 40 int v; 41 if(!primary(s, v, err)){ 42 return false; 43 } 44 if(s.empty){ 45 val = v; 46 return true; 47 } 48 switch(s.front){ 49 case '*': 50 s.popFront(); 51 int v2; 52 if(!term(s, v2, err)){ 53 return false; 54 } 55 val = v * v2; 56 return true; 57 case '/': 58 s.popFront(); 59 int v2; 60 if(!term(s, v2, err)){ 61 return false; 62 } 63 val = v * v2; 64 return true; 65 default: 66 val = v; 67 return true; 68 } 69 } 70 71 bool primary(ref Stream s, ref int val, ref Stream.Error err){ 72 import std.conv; 73 if(s.empty){ 74 err = Stream.Error(s.location, "Unexpected end of stream"); 75 return false; 76 } 77 switch(s.front){ 78 case '0' : .. case '9': 79 auto m = s.mark(); 80 do{ 81 s.popFront(); 82 }while(!s.empty && s.front >= '0' && s.front <= '9'); 83 val = to!int(s.slice(m)); 84 return true; 85 case '(': 86 s.popFront(); 87 if(!expr(s, val, err)){ 88 return false; 89 } 90 if(s.front != ')'){ 91 err = Stream.Error(s.location, "Expected ')'"); 92 } 93 s.popFront(); 94 return true; 95 default: 96 err = Stream.Error(s.location, "Unrecognized token"); 97 return false; 98 } 99 }