/* Generated by re2c */
#line 1 "main.re"
// re2c $INPUT -o $OUTPUT -b
/* re2c lesson 001_upn_calculator, main.re, (c) M. Boerger, L. Allan 2006 */
#line 43 "main.re"


#define VC_EXTRALEAN		// Exclude rarely-used stuff from Windows headers

#if _MSC_VER > 1200
#define WINVER 0x0400   // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
#endif                  // Prevents warning from vc7.1 complaining about redefinition

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <windows.h>
#include "HiResTimer.h"

static char gTestBuf[1000] = "";

/**
 * @brief Setup HiResolution timer and confirm it is working ok
 */
void InitHiResTimerAndVerifyWorking(void)
{
   double elapsed;
   HrtInit();
   HrtSetPriority(ABOVE_NORMAL_PRIORITY_CLASS);
   HrtStart();
   Sleep(100);
   elapsed = HrtElapsedMillis();
   if ((elapsed < 90) || (elapsed > 110)) {
      printf("HiResTimer misbehaving: %f\n", elapsed);
      exit(2);
   }
}

/**
 * @brief Scan for numbers in different formats
 */
int ScanFullSpeed(char *pzStrToScan, size_t lenStrToScan)
{
	unsigned char *pzCurScanPos = (unsigned char*)pzStrToScan;
	unsigned char *pzBacktrackInfo = 0;
#define YYCTYPE         unsigned char
#define YYCURSOR        pzCurScanPos
#define YYLIMIT         (pzStrToScan+lenStrToScan)
#define YYMARKER        pzBacktrackInfo
#define YYFILL(n)
	
	for(;;)
	{

#line 57 "main.c"
		{
			YYCTYPE yych;
			static const unsigned char yybm[256] = {
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				128, 128, 128, 128, 128, 128, 128, 128,
				128, 128,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0
			};
			if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
			yych = *YYCURSOR;
			if (yych <= ',') {
				if (yych <= 0x00) goto yy1;
				if (yych == '+') goto yy4;
				goto yy2;
			} else {
				if (yych <= '/') {
					if (yych <= '-') goto yy5;
					goto yy2;
				} else {
					if (yych <= '0') goto yy6;
					if (yych <= '9') goto yy7;
					goto yy2;
				}
			}
yy1:
			++YYCURSOR;
#line 98 "main.re"
			{ return 0; }
#line 114 "main.c"
yy2:
			++YYCURSOR;
yy3:
#line 99 "main.re"
			{ return 1; }
#line 120 "main.c"
yy4:
			++YYCURSOR;
#line 96 "main.re"
			{ continue; }
#line 125 "main.c"
yy5:
			++YYCURSOR;
#line 97 "main.re"
			{ continue; }
#line 130 "main.c"
yy6:
			yych = *++YYCURSOR;
			if (yych <= '/') goto yy3;
			if (yych <= '9') goto yy8;
			goto yy3;
yy7:
			++YYCURSOR;
			if (YYLIMIT <= YYCURSOR) YYFILL(1);
			yych = *YYCURSOR;
			if (yybm[0+yych] & 128) goto yy7;
#line 94 "main.re"
			{ continue; }
#line 143 "main.c"
yy8:
			++YYCURSOR;
			if (YYLIMIT <= YYCURSOR) YYFILL(1);
			yych = *YYCURSOR;
			if (yych <= '/') goto yy9;
			if (yych <= '9') goto yy8;
yy9:
#line 95 "main.re"
			{ continue; }
#line 153 "main.c"
		}
#line 100 "main.re"

	}
}

/**
 * @brief Scan for numbers in different formats
 */
int scan(char *pzStrToScan, size_t lenStrToScan)
{
	unsigned char *pzCurScanPos = (unsigned char*)pzStrToScan;
	unsigned char *pzBacktrackInfo = 0;
#define YYCTYPE         unsigned char
#define YYCURSOR        pzCurScanPos
#define YYLIMIT         (pzStrToScan+lenStrToScan)
#define YYMARKER        pzBacktrackInfo
#define YYFILL(n)
	
	for(;;)
	{

#line 176 "main.c"
		{
			YYCTYPE yych;
			static const unsigned char yybm[256] = {
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				128, 128, 128, 128, 128, 128, 128, 128,
				128, 128,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0,
				  0,   0,   0,   0,   0,   0,   0,   0
			};
			if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
			yych = *YYCURSOR;
			if (yych <= ',') {
				if (yych <= 0x00) goto yy11;
				if (yych == '+') goto yy14;
				goto yy12;
			} else {
				if (yych <= '/') {
					if (yych <= '-') goto yy15;
					goto yy12;
				} else {
					if (yych <= '0') goto yy16;
					if (yych <= '9') goto yy17;
					goto yy12;
				}
			}
yy11:
			++YYCURSOR;
#line 125 "main.re"
			{ printf("EOF\n");                           return 0; }
#line 233 "main.c"
yy12:
			++YYCURSOR;
yy13:
#line 126 "main.re"
			{ printf("ERR\n"); strcat(gTestBuf, "ERR "); return 1; }
#line 239 "main.c"
yy14:
			++YYCURSOR;
#line 123 "main.re"
			{ printf("+\n");   strcat(gTestBuf, "+ ");   continue; }
#line 244 "main.c"
yy15:
			++YYCURSOR;
#line 124 "main.re"
			{ printf("-\n");   strcat(gTestBuf, "- ");   continue; }
#line 249 "main.c"
yy16:
			yych = *++YYCURSOR;
			if (yych <= '/') goto yy13;
			if (yych <= '9') goto yy18;
			goto yy13;
yy17:
			++YYCURSOR;
			if (YYLIMIT <= YYCURSOR) YYFILL(1);
			yych = *YYCURSOR;
			if (yybm[0+yych] & 128) goto yy17;
#line 121 "main.re"
			{ printf("Num\n"); strcat(gTestBuf, "Num "); continue; }
#line 262 "main.c"
yy18:
			++YYCURSOR;
			if (YYLIMIT <= YYCURSOR) YYFILL(1);
			yych = *YYCURSOR;
			if (yych <= '/') goto yy19;
			if (yych <= '9') goto yy18;
yy19:
#line 122 "main.re"
			{ printf("Oct\n"); strcat(gTestBuf, "Oct "); continue; }
#line 272 "main.c"
		}
#line 127 "main.re"

	}
}

/**
 * @brief Show high resolution elapsed time for 10,000 and 100,000 loops
 */
void DoTimingsOfStrnCmp(void)
{
   char testStr[] = "Hello, world";
   int totLoops = 10000;
   int totFoundCount = 0;
   int foundCount = 0;
   int loop;
   int rc;
   const int progressAnd = 0xFFFFF000;
   double elapsed;

   printf("\n\n%d loops with * every %d loops to confirm\n", totLoops, ((~progressAnd) + 1));

   HrtStart();
   for (loop = 0; loop < totLoops; ++loop) {
      foundCount = 0;
      rc = strncmp(testStr, "Hello", 5);
      if (rc == 0) {
         foundCount++;
         totFoundCount++;
         if ((totFoundCount & progressAnd) == totFoundCount) {
            printf("*");
         }
      }
   }
   elapsed = HrtElapsedMillis();
   printf("\nstrncmp Elapsed for %7d loops milliseconds: %7.3f\n", totLoops, elapsed);
   printf("FoundCount each loop: %d\n", foundCount);
   printf("TotalFoundCount for all loops: %d\n", totFoundCount);

   totLoops = 100000;
   HrtStart();
   for (loop = 0; loop < totLoops; ++loop) {
      foundCount = 0;
      rc = strncmp(testStr, "Hello", 5);
      if (rc == 0) {
         foundCount++;
         totFoundCount++;
         if ((totFoundCount & progressAnd) == totFoundCount) {
            printf("*");
         }
      }
   }
   elapsed = HrtElapsedMillis();
   printf("\nstrncmp Elapsed for %7d loops milliseconds: %7.3f\n", totLoops, elapsed);
   printf("FoundCount each loop: %d\n", foundCount);
   printf("TotalFoundCount for all loops: %d\n", totFoundCount);
}

/**
 * @brief Show high resolution elapsed time for 10,000 and 100,000 loops
 */
void DoTimingsOfRe2c(void)
{
   char* testStrings[] = { "123", "1234", "+123", "01234", "-04321", "abc", "123abc" };
   const int testCount = sizeof(testStrings) / sizeof(testStrings[0]);
   int i;
   int totLoops = 10000 / testCount;  // Doing more than one per loop
   int totFoundCount = 0;
   int foundCount = 0;
   int loop;
   int rc;
   const int progressAnd = 0xFFFFF000;
   double elapsed;

   printf("\n\n%d loops with * every %d loops to confirm\n", totLoops, ((~progressAnd) + 1));

   HrtStart();
   for (loop = 0; loop < totLoops; ++loop) {
      foundCount = 0;
      strcpy(gTestBuf, "");   
      for (i = 0; i < testCount; ++i) {
         char* pzCurStr = testStrings[i];
         size_t len = strlen(pzCurStr);  // Calc of strlen slows things down ... std::string?
         rc = ScanFullSpeed(pzCurStr, len);
         if (rc == 0) {
            foundCount++;
            totFoundCount++;
            if ((totFoundCount & progressAnd) == totFoundCount) {
               printf("*");
            }
         }
      }
   }
   elapsed = HrtElapsedMillis();
   printf("\nRe2c Elapsed for %7d loops milliseconds: %7.3f\n", totLoops, elapsed);
   printf("FoundCount each loop: %d\n", foundCount);
   printf("TotalFoundCount for all loops: %d\n", totFoundCount);

   totLoops = 100000 / testCount;
   printf("\n\n%d loops with * every %d loops to confirm\n", totLoops, ((~progressAnd) + 1));

   HrtStart();
   for (loop = 0; loop < totLoops; ++loop) {
      foundCount = 0;
      strcpy(gTestBuf, "");   
      for (i = 0; i < testCount; ++i) {
         char* pzCurStr = testStrings[i];
         size_t len = strlen(pzCurStr);  // Calc of strlen slows things down ... std::string?
         rc = ScanFullSpeed(pzCurStr, len);
         if (rc == 0) {
            foundCount++;
            totFoundCount++;
            if ((totFoundCount & progressAnd) == totFoundCount) {
               printf("*");
            }
         }
      }
   }
   elapsed = HrtElapsedMillis();
   printf("\nRe2c Elapsed for %7d loops milliseconds: %7.3f\n", totLoops, elapsed);
   printf("FoundCount each loop: %d\n", foundCount);
   printf("TotalFoundCount for all loops: %d\n", totFoundCount);
}

/**
 * @brief Entry point for console app
 */
int main(int argc, char **argv)
{
   char  testStr_A[] = "123";
   char* testStr_B   = "456";
   char* testStrings[] = { "123", "1234", "+123", "01234", "-04321", "abc", "123abc" };
   const int testCount = sizeof(testStrings) / sizeof(testStrings[0]);
   int i;
   
   int rc = scan(testStr_A, 3);
   printf("rc: %d\n", rc);

   rc = scan(testStr_B, 3);
   printf("rc: %d\n", rc);

   rc = scan("789", 3);
   printf("rc: %d\n", rc);

   strcpy(gTestBuf, "");   
   for (i = 0; i < testCount; ++i) {
      char* pzCurStr = testStrings[i];
      size_t len = strlen(pzCurStr);
      scan(pzCurStr, len);
   }
   printf("%s\n", gTestBuf);
   rc = strcmp(gTestBuf, "Num Num + Num Oct - Oct ERR Num ERR ");
   if (rc == 0) {
      printf("Success\n");
   }
   else {
      printf("Failure\n");
   }
   assert(0 == rc); // Doesn't work with Release build
   
   InitHiResTimerAndVerifyWorking();

   DoTimingsOfStrnCmp();
   
   DoTimingsOfRe2c();
   
   return 0;
}
