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