1// re2c $INPUT -o $OUTPUT -b 2/* re2c lesson 001_upn_calculator, main.re, (c) M. Boerger, L. Allan 2006 */ 3/*!ignore:re2c 4 5- basic interface for string reading 6 7 . We define the macros YYCTYPE, YYCURSOR, YYLIMIT, YYMARKER, YYFILL 8 . YYCTYPE is the type re2c operates on or in other words the type that 9 it generates code for. While it is not a big difference when we were 10 using 'unsigned char' here we would need to run re2c with option -w 11 to fully support types with sieof() > 1. 12 . YYCURSOR is used internally and holds the current scanner position. In 13 expression handlers, the code blocks after re2c expressions, this can be 14 used to identify the end of the token. 15 . YYMARKER is not always being used so we set an initial value to avoid 16 a compiler warning. 17 . YYLIMIT stores the end of the input. Unfortunatley we have to use strlen() 18 in this lesson. In the next example we see one way to get rid of it. 19 . We use a 'for(;;)'-loop around the scanner block. We could have used a 20 'while(1)'-loop instead but some compilers generate a warning for it. 21 . To make the output more readable we use 're2c:indent:top' scanner 22 configuration that configures re2c to prepend a single tab (the default) 23 to the beginning of each output line. 24 . The following lines are expressions and for each expression we output the 25 token name and continue the scanner loop. 26 . The second last token detects the end of our input, the terminating zero in 27 our input string. In other scanners detecting the end of input may vary. 28 For example binary code may contain \0 as valid input. 29 . The last expression accepts any input character. It tells re2c to accept 30 the opposit of the empty range. This includes numbers and our tokens but 31 as re2c goes from top to botton when evaluating the expressions this is no 32 problem. 33 . The first three rules show that re2c actually prioritizes the expressions 34 from top to bottom. Octal number require a starting "0" and the actual 35 number. Normal numbers start with a digit greater 0. And zero is finally a 36 special case. A single "0" is detected by the last rule of this set. And 37 valid ocal number is already being detected by the first rule. This even 38 includes multi "0" sequences that in octal notation also means zero. 39 Another way would be to only use two rules: 40 "0" [0-9]+ 41 "0" | ( [1-9] [0-9]* ) 42 A full description of re2c rule syntax can be found in the manual. 43*/ 44 45#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers 46 47#if _MSC_VER > 1200 48#define WINVER 0x0400 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later. 49#endif // Prevents warning from vc7.1 complaining about redefinition 50 51#include <stdio.h> 52#include <stdlib.h> 53#include <assert.h> 54#include <string.h> 55#include <windows.h> 56#include "HiResTimer.h" 57 58static char gTestBuf[1000] = ""; 59 60/** 61 * @brief Setup HiResolution timer and confirm it is working ok 62 */ 63void InitHiResTimerAndVerifyWorking(void) 64{ 65 double elapsed; 66 HrtInit(); 67 HrtSetPriority(ABOVE_NORMAL_PRIORITY_CLASS); 68 HrtStart(); 69 Sleep(100); 70 elapsed = HrtElapsedMillis(); 71 if ((elapsed < 90) || (elapsed > 110)) { 72 printf("HiResTimer misbehaving: %f\n", elapsed); 73 exit(2); 74 } 75} 76 77/** 78 * @brief Scan for numbers in different formats 79 */ 80int ScanFullSpeed(char *pzStrToScan, size_t lenStrToScan) 81{ 82 unsigned char *pzCurScanPos = (unsigned char*)pzStrToScan; 83 unsigned char *pzBacktrackInfo = 0; 84#define YYCTYPE unsigned char 85#define YYCURSOR pzCurScanPos 86#define YYLIMIT (pzStrToScan+lenStrToScan) 87#define YYMARKER pzBacktrackInfo 88#define YYFILL(n) 89 90 for(;;) 91 { 92/*!re2c 93 re2c:indent:top = 2; 94 [1-9][0-9]* { continue; } 95 [0][0-9]+ { continue; } 96 "+" { continue; } 97 "-" { continue; } 98 "\000" { return 0; } 99 [^] { return 1; } 100*/ 101 } 102} 103 104/** 105 * @brief Scan for numbers in different formats 106 */ 107int scan(char *pzStrToScan, size_t lenStrToScan) 108{ 109 unsigned char *pzCurScanPos = (unsigned char*)pzStrToScan; 110 unsigned char *pzBacktrackInfo = 0; 111#define YYCTYPE unsigned char 112#define YYCURSOR pzCurScanPos 113#define YYLIMIT (pzStrToScan+lenStrToScan) 114#define YYMARKER pzBacktrackInfo 115#define YYFILL(n) 116 117 for(;;) 118 { 119/*!re2c 120 re2c:indent:top = 2; 121 [1-9][0-9]* { printf("Num\n"); strcat(gTestBuf, "Num "); continue; } 122 [0][0-9]+ { printf("Oct\n"); strcat(gTestBuf, "Oct "); continue; } 123 "+" { printf("+\n"); strcat(gTestBuf, "+ "); continue; } 124 "-" { printf("-\n"); strcat(gTestBuf, "- "); continue; } 125 "\000" { printf("EOF\n"); return 0; } 126 [^] { printf("ERR\n"); strcat(gTestBuf, "ERR "); return 1; } 127*/ 128 } 129} 130 131/** 132 * @brief Show high resolution elapsed time for 10,000 and 100,000 loops 133 */ 134void DoTimingsOfStrnCmp(void) 135{ 136 char testStr[] = "Hello, world"; 137 int totLoops = 10000; 138 int totFoundCount = 0; 139 int foundCount = 0; 140 int loop; 141 int rc; 142 const int progressAnd = 0xFFFFF000; 143 double elapsed; 144 145 printf("\n\n%d loops with * every %d loops to confirm\n", totLoops, ((~progressAnd) + 1)); 146 147 HrtStart(); 148 for (loop = 0; loop < totLoops; ++loop) { 149 foundCount = 0; 150 rc = strncmp(testStr, "Hello", 5); 151 if (rc == 0) { 152 foundCount++; 153 totFoundCount++; 154 if ((totFoundCount & progressAnd) == totFoundCount) { 155 printf("*"); 156 } 157 } 158 } 159 elapsed = HrtElapsedMillis(); 160 printf("\nstrncmp Elapsed for %7d loops milliseconds: %7.3f\n", totLoops, elapsed); 161 printf("FoundCount each loop: %d\n", foundCount); 162 printf("TotalFoundCount for all loops: %d\n", totFoundCount); 163 164 totLoops = 100000; 165 HrtStart(); 166 for (loop = 0; loop < totLoops; ++loop) { 167 foundCount = 0; 168 rc = strncmp(testStr, "Hello", 5); 169 if (rc == 0) { 170 foundCount++; 171 totFoundCount++; 172 if ((totFoundCount & progressAnd) == totFoundCount) { 173 printf("*"); 174 } 175 } 176 } 177 elapsed = HrtElapsedMillis(); 178 printf("\nstrncmp Elapsed for %7d loops milliseconds: %7.3f\n", totLoops, elapsed); 179 printf("FoundCount each loop: %d\n", foundCount); 180 printf("TotalFoundCount for all loops: %d\n", totFoundCount); 181} 182 183/** 184 * @brief Show high resolution elapsed time for 10,000 and 100,000 loops 185 */ 186void DoTimingsOfRe2c(void) 187{ 188 char* testStrings[] = { "123", "1234", "+123", "01234", "-04321", "abc", "123abc" }; 189 const int testCount = sizeof(testStrings) / sizeof(testStrings[0]); 190 int i; 191 int totLoops = 10000 / testCount; // Doing more than one per loop 192 int totFoundCount = 0; 193 int foundCount = 0; 194 int loop; 195 int rc; 196 const int progressAnd = 0xFFFFF000; 197 double elapsed; 198 199 printf("\n\n%d loops with * every %d loops to confirm\n", totLoops, ((~progressAnd) + 1)); 200 201 HrtStart(); 202 for (loop = 0; loop < totLoops; ++loop) { 203 foundCount = 0; 204 strcpy(gTestBuf, ""); 205 for (i = 0; i < testCount; ++i) { 206 char* pzCurStr = testStrings[i]; 207 size_t len = strlen(pzCurStr); // Calc of strlen slows things down ... std::string? 208 rc = ScanFullSpeed(pzCurStr, len); 209 if (rc == 0) { 210 foundCount++; 211 totFoundCount++; 212 if ((totFoundCount & progressAnd) == totFoundCount) { 213 printf("*"); 214 } 215 } 216 } 217 } 218 elapsed = HrtElapsedMillis(); 219 printf("\nRe2c Elapsed for %7d loops milliseconds: %7.3f\n", totLoops, elapsed); 220 printf("FoundCount each loop: %d\n", foundCount); 221 printf("TotalFoundCount for all loops: %d\n", totFoundCount); 222 223 totLoops = 100000 / testCount; 224 printf("\n\n%d loops with * every %d loops to confirm\n", totLoops, ((~progressAnd) + 1)); 225 226 HrtStart(); 227 for (loop = 0; loop < totLoops; ++loop) { 228 foundCount = 0; 229 strcpy(gTestBuf, ""); 230 for (i = 0; i < testCount; ++i) { 231 char* pzCurStr = testStrings[i]; 232 size_t len = strlen(pzCurStr); // Calc of strlen slows things down ... std::string? 233 rc = ScanFullSpeed(pzCurStr, len); 234 if (rc == 0) { 235 foundCount++; 236 totFoundCount++; 237 if ((totFoundCount & progressAnd) == totFoundCount) { 238 printf("*"); 239 } 240 } 241 } 242 } 243 elapsed = HrtElapsedMillis(); 244 printf("\nRe2c Elapsed for %7d loops milliseconds: %7.3f\n", totLoops, elapsed); 245 printf("FoundCount each loop: %d\n", foundCount); 246 printf("TotalFoundCount for all loops: %d\n", totFoundCount); 247} 248 249/** 250 * @brief Entry point for console app 251 */ 252int main(int argc, char **argv) 253{ 254 char testStr_A[] = "123"; 255 char* testStr_B = "456"; 256 char* testStrings[] = { "123", "1234", "+123", "01234", "-04321", "abc", "123abc" }; 257 const int testCount = sizeof(testStrings) / sizeof(testStrings[0]); 258 int i; 259 260 int rc = scan(testStr_A, 3); 261 printf("rc: %d\n", rc); 262 263 rc = scan(testStr_B, 3); 264 printf("rc: %d\n", rc); 265 266 rc = scan("789", 3); 267 printf("rc: %d\n", rc); 268 269 strcpy(gTestBuf, ""); 270 for (i = 0; i < testCount; ++i) { 271 char* pzCurStr = testStrings[i]; 272 size_t len = strlen(pzCurStr); 273 scan(pzCurStr, len); 274 } 275 printf("%s\n", gTestBuf); 276 rc = strcmp(gTestBuf, "Num Num + Num Oct - Oct ERR Num ERR "); 277 if (rc == 0) { 278 printf("Success\n"); 279 } 280 else { 281 printf("Failure\n"); 282 } 283 assert(0 == rc); // Doesn't work with Release build 284 285 InitHiResTimerAndVerifyWorking(); 286 287 DoTimingsOfStrnCmp(); 288 289 DoTimingsOfRe2c(); 290 291 return 0; 292} 293