ESP_IOT v2.5
IOT ESP Coding
TokenParser.cpp
Go to the documentation of this file.
1#include "TokenParser.h"
2
3#ifdef WILDCARD_DEVICE_NAME_SUPPORT
4
5/*
6<identifier> ::= {characters A-Z,a-z,0-9,_}
7<notModifier> ::= '!'
8<modifier> ::= <notModifier>
9<wildcardAny> ::= '*'
10<wildcard> ::= <wildcardAny>
11<booleanAnd> ::= '&'
12<booleanOr> ::= '|'
13<booleanOps> ::= <booleanAnd> | <booleanOr> | <null>
14<queryElement> ::= { [<modifier>] [<wildcard>] <identifier> [<wildcard>] }
15<queryPart> ::= { <queryElement> <booleanOps> }
16
17<identifierFollow> ::= {anything not <identifier> }
18eg. ! M5* -> <notModifier> <identifier> <wildcard>
19!*M5* & ! *GEN3* -> <wildcard=*> <identifier=M5> <wildcard=*> <booleanOps=&> <wildcard=*> <identifier=GEN3>
20means: any non M5* and not *GEN3*
21
22
23Currently presidence will be AND over OR (or just left to right)
24*/
25
26//!retrieves the parsed values
27
28//!the tokens in the token array
29typedef enum
30{
38
39//!max length of an identifier..
40const int _identifierMaxLen= 30;
41//! storage for the current identifier
43// !where in the current identifier
45
46typedef struct identifierStruct
47{
51 boolean notModifier;
53
54//!so now a query is { IdentifierStruct <booleanAnd/Or> }
55
56//!the max number of identifiers
58//!index into _identifiers array
60//! array of identifiers ..
62
63const int _tokensMax = 10;
65//!index into _tokens array
67
68//!whether in an identifier parsing
70
71//!pushes token onto token stack
73{
74 SerialLots.printf("\nPushToken[%d] %d\n", _tokensStackPointer, token);
75
77 {
78 SerialMin.println(" *** Over the token max ***");
79 return;
80 }
82}
83
84//!get the current top of stack token
86{
87 //if stack empty .. return null_enum
88 if (_tokensStackPointer == 0)
89 return null_enum;
90 //! otherwise grab the top
92}
93
94//!get the current top of stack token, and move the token stack pointer
96{
97 TokensEnum result;
98 //if stack empty .. return null_enum
99 if (_tokensStackPointer == 0)
100 result = null_enum;
101 else
102 {
103 //!else pop
106 }
107 SerialLots.printf("\npop[%d] = %d\n", _tokensStackPointer, result);
108 return result;
109}
110
111//!pushes identifier onto identifier stack, while also inserting a token for identifier
112void pushIdentifier(char *identifier)
113{
114 SerialLots.printf("\nPushId %s\n", identifier);
115
117 //! now save Identifier
118 strcpy(_identifierStructs[_identifierStructsIndex++].identifier, identifier);
119}
120
121//! how many tokens
123{
124 return _tokensStackPointer;
125}
126//!how many identifiers
128{
130}
131//!get the nth token
133{
134 return _tokens[num];
135}
136//!the nth identifier
137char *getIdentifier(int num)
138{
139 return _identifierStructs[num].identifier;
140}
141
142//!grab full identifier struct (Pointer?)
144{
145 return _identifierStructs[num];
146}
147
148//!adds a valie character to an identifier
150{
153 _identifier[_identifierIndex] = (char)NULL;
154}
155//!initi for each new identifier
156void initIdentifier(char c)
157{
160}
161
162//!finished parsing an identifier
164{
165 _parsingIdentifier = false;
167}
168
169//! whether the character is a valid identifier character
170//! 1.22.24 adding ":" so fits a BLE address
171//! DevQuery: !M5Laybrinth & !84:cc:a8:7a:f6:aa
172boolean validIdentifierChar(char c)
173{
174 boolean valid = false;
175 if (c == '_')
176 valid = true;
177 else if (c >= 'A' && c <= 'Z')
178 valid = true;
179 else if (c >= 'a' && c <= 'z')
180 valid = true;
181 else if (c >= '0' && c <= '9')
182 valid = true;
183 else if (c == ':')
184 valid = true;
185 else valid = false;
186 return valid;
187}
188
189//!push identifier .. looks at the stack and fills in the identifier object
190//!called after seeing a & or | (the follow set of the identifier, after a *)*
192{
193 //!the index is already 1 past..
194 int identifierStructsIndex = _identifierStructsIndex-1;
195 SerialLots.printf("\nprocessIdentifier[%d]\n", identifierStructsIndex);
196 //! look at stack
197 // the _identifierStructsIndex is the identifier we will modify..
199 if (top == wildcardAny_enum)
200 {
201 SerialLots.printf("wildcardAny_enum\n");
202
203 _identifierStructs[identifierStructsIndex].wildcardAfter = true;
204 top = popTokenStack();
205 }
206 top = topOfTokenStack();
207 if (top != identifier_enum)
208 {
209 SerialMin.printf("*** Syntax error: expected identifier, found: %d\n", top);
210 }
211 else
212 {
213 SerialLots.printf("identifier_enum\n");
214
215 // should be identifier we are looking for..
216 top = popTokenStack();
217 }
218 top = topOfTokenStack();
219 if (top == wildcardAny_enum)
220 {
221 SerialLots.printf("wildcardAny_enum\n");
222
223 _identifierStructs[identifierStructsIndex].wildcardBefore = true;
224 top = popTokenStack();
225 }
226 top = topOfTokenStack();
227 if (top == notModifier_enum)
228 {
229 SerialLots.printf("notModifier_enum\n");
230
231 _identifierStructs[identifierStructsIndex].notModifier = true;
232 top = popTokenStack();
233 SerialLots.printf("token = %d\n", top);
234 }
235
236 //!replace the stack with our filled out identifier
238
239}
240
241//!initialize the parser
243{
247 _parsingIdentifier = false;
248 for (int i=0; i< _identifierStructsMax; i++)
249 {
253 }
254}
255
256
257//!parses a line of text, returning the number of tokens..
259{
260//! NOTE: doesn't support the BLE addresses like:
261//! DevQuery: !M5Laybrinth & !84:cc:a8:7a:f6:aa
262 SerialTemp.printf("\nDevQuery: %s\n", line);
263
264 //! initialize the variables for parsing this line
265 initParser();
266 //! if no query params, then make it an identifier and exit
267 if (!stringIsQuery_mainModule(line))
268 {
269 SerialLots.println("*** Not a query, so optimze to just identifier");
270 pushIdentifier(line);
271 return;
272 }
273 while (*line)
274 {
275 char c = *line++;
276 SerialLots.print(c);
277 if (validIdentifierChar(c))
278 {
279 //! if parsing still then add to identifier
281 {
283 }
284 else
285 {
286 //! start a new identifier..
287 _parsingIdentifier = true;
288 //! init the identifier
290 }
291 }
292 //! else not valid identifier (so a follow..)
293 else
294 {
295 boolean finishIdNeeded = false;
296 //! done parsing if not a valid identifier character
298 {
300 finishIdNeeded = true;
301 //! finishIdNeeded is before pushing another token, unless a not or wildcard
302 }
303 //! now classify this char
304 //! if an identifier modifier
305 if (c == '!' || c == '*')
306 {
307 switch (c)
308 {
309 //! ! and * belong to the identifier object
310 //! if a modifier of ident (~ or *) then push the token,
311 //! and process the identifier
312 case '!':
314 break;
315 case '*':
317 break;
318 }
319 if (finishIdNeeded)
321 }
322 else
323 {
324 //! an operator or space
325 //! if inside an identifier, finish it first
326 if (finishIdNeeded)
328 //! process the token
329 switch (c)
330 {
331 //!& and | are expression modifiers
332 case '&':
334 break;
335 case '|':
337 break;
338 case ' ':
339 break;
340 default:
341 //** Invalid character **.
342 SerialTemp.println(" *** INVALID CHAR ***");
343 break;
344 }
345 } // switch
346
347 }
348 } //while
349
350 //! if end of line, and was parsing an identifier .. then finish
352 {
355 }
356
357}
358
359
360//! These are CASE SENSITIVE matches ...
361//!matches name with wildcards and the idToMatch
362//!name is what is being queried, the idQueryStruct is the QUERY
363boolean nameMatchesWildcardQuery(char *name, IdentifierStruct idQueryStruct)
364{
365 char *queryIdToMatch = idQueryStruct.identifier;
366 boolean wildcardBefore = idQueryStruct.wildcardBefore;
367 boolean wildcardAfter = idQueryStruct.wildcardAfter;
368 boolean wildcardNot = idQueryStruct.notModifier;
369 //default
370 boolean match = false;
371
372 SerialLots.printf("%s - idQuery(%s), before=%d,after=%d,not=%d\n", name, queryIdToMatch, wildcardBefore, wildcardAfter, wildcardNot);
373 //!@see https://legacy.cplusplus.com/reference/cstring/strncmp/
374 //! eg. idToMatch == M5 and wildcard after and before, then just search for idToMatch in name
375 //! If not before, then starts with ...
376 //! if non, then strmatch
377 if (wildcardBefore && wildcardAfter)
378 // contains .. ptr to first occurance of idToMatch in name
379 match = (strstr(name, queryIdToMatch)!=NULL);
380 else if (wildcardAfter)
381 // starts with ..
382 match = (strncmp(name, queryIdToMatch, strlen(queryIdToMatch))==0);
383 else if (wildcardBefore)
384 {
385 int queryIdLen = strlen(queryIdToMatch);
386 int nameLen = strlen(name);
387 // ends with..
388 //eg: *Rainier (and name == M5Rainier)
389 // and *Rainier matched Rainier
390 // *Room1 and Scooby_Room1 should match
391 // diff = *R and SR -> queryLen = 1, our len = 2, 2 -1 = 1 CORRECT
392 // just look for the last idLen characters of name
393 if (nameLen >= queryIdLen)
394 {
395 //start search at N into name
396 char *startInName = name + nameLen - queryIdLen;
397 match = strcmp(startInName, queryIdToMatch) == 0;
398 }
399 }
400 else
401 // is identical
402 match = strcmp(name, queryIdToMatch)==0;
403
404 //!see if there was a NOT (!)
405 if (wildcardNot)
406 match = !match;
407 return match;
408}
409
410
411//! whether the stirng is a potential query
412boolean stringIsQuery_mainModule(char *line)
413{
414 //strpbrk = first occurance of any characters in str2 in str1
415 boolean isQuery = strpbrk(line, (char*)"|*&!") != NULL;
416 return isQuery;
417}
418
419//!now need to process the token tree to see if name1 and name2 match the query
420//!eg. ! *name* & name2 ...
421//!wildcards after name make it slightly complicated
422//! SO: look for wildcards before and after, and the id. then decide if that matches
423//! before the boolean and notmodifier applied
425{
426 //!basically for each identifier in the query, the names (1&2) have to be compared each time..
427 boolean match = true;
428 int tokensIndex = 0;
429 int idIndex = 0;
430
431 //!what the last boolean_enum was..
432 TokensEnum boolean_enum = null_enum;
433 IdentifierStruct lastIdentifier;
434 // each identifier has a match..
435 boolean thisMatch = false;
436
437 while (tokensIndex < numTokens())
438 {
439 // A or B and D
440 TokensEnum token = getToken(tokensIndex++);
441 switch (token)
442 {
443 case booleanOr_enum:
444 boolean_enum = booleanOr_enum;
445 break;
446 case booleanAnd_enum:
447 boolean_enum = booleanAnd_enum;
448 break;
449 case identifier_enum:
450 lastIdentifier = getIdentifierStruct(idIndex++);
451 thisMatch = nameMatchesWildcardQuery(name, lastIdentifier);
452 if (boolean_enum == null_enum)
453 {
454 // first time, reset of times the enum will be set..
455 // good if only Identifier too.. if false .. true & false = false
456 match = match && thisMatch;
457 }
458 else
459 {
460 //! the result of A <> B
461 // at the B, eg A or B | A and B
462 if (boolean_enum == booleanOr_enum)
463 match = match || thisMatch;
464 else
465 match = match && thisMatch;
466 // reset, should never read again
467 boolean_enum = null_enum;
468 }
469 SerialLots.printf("thisMatch = %d, match = %d\n", thisMatch, match);
470
471 break;
472 // ID or ID and ID
473 // null ID or IDx
474 };
475 }
476 return match;
477}
478
479//#define TEST_PARSER
480#ifdef TEST_PARSER
481
482//!walks the tree printing it out..
483void printTokenTree()
484{
485 //SerialLots.printf("tokens=%d, id=%d\n", numTokens(), numIdentifiers());
486 SerialTemp.println("TOKEN TREE..");
487
488 int tokensIndex = 0;
489 int idIndex = 0;
490 while (tokensIndex < numTokens())
491 {
492 TokensEnum token = getToken(tokensIndex);
493 SerialTemp.printf("Token [%d]= ", tokensIndex);
494 tokensIndex++;
495 switch (token)
496 {
497 case notModifier_enum:
498 SerialTemp.println("notModifier_enum");
499 break;
500 case wildcardAny_enum:
501 SerialTemp.println("wildcardAny_enum");
502 break;
503 case booleanOr_enum:
504 SerialTemp.println("booleanOr_enum");
505 break;
506 case booleanAnd_enum:
507 SerialTemp.println("booleanAnd_enum");
508 break;
509 case identifier_enum:
510 {
511 IdentifierStruct idQueryStruct = getIdentifierStruct(idIndex++);
512 char *id = idQueryStruct.identifier;
513 SerialTemp.printf("identifier_enum: %s%s%s%s\n",
514 idQueryStruct.notModifier?"!":"",
515 idQueryStruct.wildcardBefore?"*":"",
516 id,
517 idQueryStruct.wildcardAfter?"*":""
518 );
519
520 }
521 break;
522 };
523 }
524}
525//!printout
526void testMatchResult(char*query, boolean expectedBool)
527{
528 boolean match = queryMatchesName_mainModule(query);
529 SerialTemp.printf("query '%s' ", query);
530 if (match != expectedBool)
531 SerialTemp.printf("!= expected: ");
532 else
533 SerialTemp.printf("== matched : ");
534 SerialTemp.printf("%s\n", expectedBool?(char*)"MATCH":(char*)"NO-MATCH");
535
536}
537
538boolean _firstTimeParserTest = true;
539
540//!test
541void testParser_mainModule()
542{
543 int tokens;
544 boolean match;
545 parseQueryLine_mainModule((char*)"!M5WRR");
546 //printTokenTree();
547 testMatchResult((char*)"M5WRR", false);
548 testMatchResult((char*)"M5Rainier", true);
549
550 parseQueryLine_mainModule((char*)"!M5WRR & !DukeGEN3");
551 //printTokenTree();
552 testMatchResult((char*)"M5WRR", false);
553 testMatchResult((char*)"DukeGEN3", false);
554 testMatchResult((char*)"ScoobyDoo", true);
555 testMatchResult((char*)"ScottyGEN3", true);
556
557 parseQueryLine_mainModule((char*)"M5* | DukeGEN3");
558 testMatchResult((char*)"M5Scooby", true);
559 testMatchResult((char*)"DukeGEN3", true);
560
561
562 parseQueryLine_mainModule((char*)"!*GEN3*");
563 testMatchResult((char*)"M5Scooby", true);
564 testMatchResult((char*)"DukeGEN3", false);
565
566 parseQueryLine_mainModule((char*)"!M5* ");
567 testMatchResult((char*)"M5Scooby", false);
568 testMatchResult((char*)"DukeGEN3", true);
569
570 parseQueryLine_mainModule((char*)"!M5* & !*GEN3*");
571 testMatchResult((char*)"M5Scooby", false);
572 testMatchResult((char*)"DukeGEN3", false);
573 testMatchResult((char*)"M5DukeGEN3", false);
574 testMatchResult((char*)"M5DukeGEN3", true);
575
576 parseQueryLine_mainModule((char*)"!M5* | *GEN3*");
577 testMatchResult((char*)"M5Scooby", false);
578 testMatchResult((char*)"DukeGEN3", true);
579 testMatchResult((char*)"M5DukeGEN3", false); //interesting
580
581 parseQueryLine_mainModule((char*)"!M5*");
582 testMatchResult((char*)"M5WRR", false);
583 testMatchResult((char*)"DukeGEN3", true);
584
585 parseQueryLine_mainModule((char*)"!M5WRR");
586 testMatchResult((char*)"M5WRR", false);
587 testMatchResult((char*)"M5Scooby", true);
588
589 parseQueryLine_mainModule((char*)"*M5* |*GEN3* | ScoobyDoo");
590 testMatchResult((char*)"M5Scooby", true);
591 testMatchResult((char*)"GEN3Scott", true);
592 testMatchResult((char*)"ScoobyDoo", true);
593 testMatchResult((char*)"Duke", false);
594 testMatchResult((char*)"M5Duke", true);
595
596 parseQueryLine_mainModule((char*)"ScoobyDoo");
597 testMatchResult((char*)"ScoobyDoo", true);
598 testMatchResult((char*)"Duke", false);
599
600 parseQueryLine_mainModule((char*)"!*M5* | *GEN3* &ScoobyDoo");
601 testMatchResult((char*)"ScoobyDoo", true);
602 testMatchResult((char*)"M5WRR", false);
603 testMatchResult((char*)"GEN3Scott", true);
604
605 parseQueryLine_mainModule((char*)"!*M5* | *GEN3* | ScoobyDoo");
606 testMatchResult((char*)"ScoobyDoo", true);
607 testMatchResult((char*)"M5WRR", false);
608 testMatchResult((char*)"GEN3Scott", true);
609
610 //! all Room1 which are M5. eg. Room1_M5Scooby
611 parseQueryLine_mainModule((char*)"Room1_* & *M5*");
612 testMatchResult((char*)"Room1_M5Scooby", true);
613 testMatchResult((char*)"Room1_GEN3", false);
614 testMatchResult((char*)"Room2_GEN3", false);
615 testMatchResult((char*)"M5WRR", false);
616
617 //! all Room1 which are M5. eg. Room1_M5Scooby
618 parseQueryLine_mainModule((char*)"Room1_* | *M5*");
619 testMatchResult((char*)"Room1_M5Scooby", true);
620 testMatchResult((char*)"Room1_GEN3", true);
621 testMatchResult((char*)"Room2_GEN3", false);
622 testMatchResult((char*)"Room2_M5", true);
623 testMatchResult((char*)"M5WRR", true);
624
625 //! all Room1 which are M5. eg. Room1_M5Scooby
626 parseQueryLine_mainModule((char*)"Room1_*");
627 testMatchResult((char*)"Room1_M5Scooby", true);
628 testMatchResult((char*)"Room1_GEN3", true);
629 testMatchResult((char*)"Room2_GEN3", false);
630
631 //! all Room1 which are M5. eg. Room1_M5Scooby
632 parseQueryLine_mainModule((char*)"*Room1");
633 testMatchResult((char*)"Scooby_Room1", true);
634 testMatchResult((char*)"Scooby_Room1_GEN3", false);
635 testMatchResult((char*)"Room1", true);
636 testMatchResult((char*)"Room2", false);
637
638 //! all Room1 which are M5. eg. Room1_M5Scooby
639 parseQueryLine_mainModule((char*)"*GEN3");
640 testMatchResult((char*)"Scooby_GEN3", true);
641 testMatchResult((char*)"Scooby_GEN3_Room1", false);
642 testMatchResult((char*)"GEN3", true);
643 testMatchResult((char*)"GEN2", false);
644
645 //! all Room1 which are M5. eg. Room1_M5Scooby
646 parseQueryLine_mainModule((char*)"!*GEN3");
647 testMatchResult((char*)"Scooby_GEN3", false);
648 testMatchResult((char*)"Scooby_GEN3_Room1", true);
649 testMatchResult((char*)"GEN3", false);
650 testMatchResult((char*)"GEN2", true);
651 testMatchResult((char*)"M5Scooby", true);
652 testMatchResult((char*)"DukeGEN3", false);
653 testMatchResult((char*)"M5DukeGEN3", false);
654}
655
656#endif //test parser
657
658//! setup a test ..
660{
661#ifdef TEST_PARSER
662 if (_firstTimeParserTest)
663 {
664 _firstTimeParserTest = false;
665 testParser_mainModule();
666 }
667#endif
668}
669
670#else
671
672
673//!parses a line of text, The caller then uses queryMatchesName() to see if their name matches
674void parseQueryLine_mainModule(char *line)
675{
676 //noop
677}
678
679//!now need to process the token tree to see if name1 and name2 match the query
680//!eg. ! *name* & name2 ...
681//!wildcards after name make it slightly complicated
682//! SO: look for wildcards before and after, and the id. then decide if that matches
683//! before the boolean and notmodifier applied
684boolean queryMatchesName_mainModule(char*name)
685{
686 return true;
687}
688
689//! whether the stirng is a potential query. This can be used, but it is also used by the parseQueryLine
690//! to optimize out the original dev:name query.
691boolean stringIsQuery_mainModule(char *line)
692{
693 //noop
694}
695
696//! setup for the token parser (really just for testing)
698{
699 //noop
700}
701#endif
702
703//! storage for the current identifier
705
706//! 3.23.25 rainy weekend
707//! create a JSON string from the SemanticMarker
708//! https://semanticmarker.org/bot/setdevice/scott@konacurrents.com/PASS/M5AtomSocket/socket/on}
709//! Create a JSON knowing the "bot" syntax, eg. setdevice/USER/PASS/device/<set>/<flag>
710//! and others like set etc.
711//! Maybe not 'dev' here. Others cmddevice/USER/PASS
712//! return: {'set':<set>,"dev':
713//! set- sends the message (command/value) to all device
714//! Supports these for now:
715//!GET /set/{username}/{password}/{command}/{value}
716//!GET /send/{username}/{password}/{request}
717//! only support 'device' ones
718//!GET /setdevice/{username}/{password}/{devicename}/{command}/{value}
719//!GET /senddevice/{username}/{password}/{device}/{request}
720//!return "" if not valid
721char *semanticMarkerToJSON_TokenParser(char* semanticMarker)
722{
723 /*
724 Token = https:
725 Token = semanticmarker.org
726 Token = bot
727 Token = setdevice
728 Token = scott@konacurrents.com
729 Token = PASS
730 Token = M5AtomSocket
731 Token = socket
732 Token = on
733 */
734 char *rest = NULL;
735 char *token;
736 int arrayIndex = 0;
737 SerialLots.printf("\nTokens for: %s\n",semanticMarker);
738
739#define setIndex 3
740#define userIndex 4
741#define passIndex 5
742#define deviceIndex 6
743#define cmdIndex 7
744#define flagIndex 8
745
746 strcpy(_JSON_String_mainModule,"{\n");
747
748 int setDeviceFlag = -1;
749 // if 0 .. then sendDevice
750 arrayIndex = 0;
751 char buffer[50];
752 //
753 for (char *token= strtok(semanticMarker,"/"); token!= NULL; token= strtok(NULL, "/"))
754 {
755 //printf("Token[%d] = %s\n", arrayIndex, token);
756 switch (arrayIndex)
757 {
758 case setIndex:
759 {
760 if (strcmp(token,"setdevice")==0)
761 setDeviceFlag = 1;
762 else if (strcmp(token,"cmddevice")==0)
763 setDeviceFlag = 0;
764 else
765 {
766 setDeviceFlag = -1;
767 //! not supported
768 token = NULL;
769 strcpy(_JSON_String_mainModule,"");
770 }
771 }
772 break;
773 case deviceIndex:
774 sprintf(buffer,"'dev':'%s',\n", token);
775 //printf("%s,\n",buffer);
776 strcat(_JSON_String_mainModule, buffer);
777 break;
778 case cmdIndex:
779 //! if set then there will be more .. so add ','
780 //! if send then this is the end (no ',')
781 if (setDeviceFlag)
782 sprintf(buffer,"'%s':'%s',\n","set",token);
783 else if (setDeviceFlag == 0)
784 sprintf(buffer,"'%s':'%s'\n", "cmd",token);
785
786 //printf("%s,\n",buffer);
787 strcat(_JSON_String_mainModule, buffer);
788 break;
789 case flagIndex:
790 sprintf(buffer,"'val':'%s'\n", token);
791 //printf("%s\n",buffer);
792 strcat(_JSON_String_mainModule, buffer);
793 break;
794 }
795 arrayIndex++;
796 }
797 int indexLen = arrayIndex - 1;
798 SerialLots.printf("#IndexLen= %d\n", indexLen);
799 switch (setDeviceFlag)
800 {
801 case 1: // setDevice
802 if (indexLen != 8)
803 {
804 SerialDebug.printf(" *** Wrong syntax setDevice *** \n");
805 }
806 break;
807 case 0: // sendDevice
808 if (indexLen != 7)
809 {
810 SerialDebug.printf(" *** Wrong syntax sendDevice *** \n");
811 }
812 break;
813
814 case -1: // unknown
815 break;
816
817 }
818 if (setDeviceFlag >= 0)
819 strcat(_JSON_String_mainModule, "}");
820
821 //! replace ' with "
822 for (char* p = _JSON_String_mainModule; *p; p++)
823 {
824 if (p[0] == '\'')
825 p[0]= '\"';
826 }
827 SerialDebug.printf("_JSON_String_mainModule= \n%s\n", _JSON_String_mainModule);
828
830}
831
832//! global for returning..
834//! 3.29.25 Raiiiinier Beeer movie last night
835//! add returning a UUID.FLOWNUM if valid, or nil if nota
836//! note "flow" .. not flownum
837//! uuid=x&flow=y& .. flownum could be the last .. so end-of-line
838char *parseSM_For_UUID_Flownum(char* semanticMarker)
839{
840 //! syntax: uuid=X&flownum=Y
841 /*
842
843 Token[0] = https:
844 Token[1] = semanticmarker.org
845 Token[2] = bot
846 Token[3] = smart?uuid=UUID_343434&flow=239293&morestuff=33
847 // first break on "smart?" .. or advance..
848 // need: next step break on "&"
849 tokens: uuid=askdasjfk
850 flow=ksjdfkasjdfk
851 next step (break on "="
852 uuid,adkfjaskdf
853 flow,kdjfkasdf
854 */
855 char *rest = NULL;
856 char *token;
857 int arrayIndex = 0;
858
859
860 char _uuidString[40];
861 char _flowString[40];
862 strcpy(_uuidString,"");
863 strcpy(_flowString,"");
864 arrayIndex = 0;
865 //! needed to copy semanticMarker .. as the code below broke the callers' value to "https:" .. SIDE EFFECT
866 char str[500];
867 strcpy(str,semanticMarker);
868 strcpy(_sm_for_UUID_Flownum,"");
869
870 //! look for tokens
871 for (char *token= strtok(str,"/"); token!= NULL; token= strtok(NULL, "/"))
872 {
873 SerialLots.printf("Token[%d] = %s\n", arrayIndex, token);
874 switch (arrayIndex)
875 {
876#define smartSwitch 3
877 case smartSwitch:
878 {
879 /*
880 Token[3] = smart?uuid=UUID_343434&flow=239293&morestuff=33
881 // first break on "smart?" .. or advance..
882 // need: next step break on "&"
883 tokens: uuid=askdasjfk
884 flow=ksjdfkasjdfk
885 next step (break on "="
886 uuid,adkfjaskdf
887 flow,kdjfkasdf
888 */
889 char *smartIndex = strstr(token,"smart?");
890 if (smartIndex)
891 smartIndex += strlen("smart?");
892
893 //! break by '&'
894 for (char*amper = strtok(smartIndex,"&"); amper!=NULL; amper=strtok(NULL,"&"))
895 {
896 char *equalIndex = strchr(amper,'=');
897
898 char queryString[100];
899 int len = equalIndex - amper;
900 strncpy(queryString, amper, len);
901 queryString[len] = '\0';
902 SerialLots.printf("%s - %d\n", queryString, len);
903
904 //! advance quealIndex past the equal
905 equalIndex++;
906 if (strcmp(queryString,"uuid")==0)
907 {
908 strcpy(_uuidString, equalIndex);
909 }
910 else if (strcmp(queryString,"flow")==0)
911 {
912 strcpy(_flowString, equalIndex);
913 }
914 SerialLots.printf("query ={%s,%s}\n", queryString, equalIndex);
915 }
916 }
917 break;
918 arrayIndex++;
919 }
920 if (strlen(_uuidString) > 0 && strlen(_flowString) > 0)
921 {
922 sprintf(_sm_for_UUID_Flownum,"%s.%s",_uuidString, _flowString);
923 SerialDebug.printf("SemanticMarker: %s\n", _sm_for_UUID_Flownum);
924 }
926
927 }
929}
char * _uuidString
void initParser()
initialize the parser
TokensEnum topOfTokenStack()
get the current top of stack token
Definition: TokenParser.cpp:85
const int _identifierStructsMax
so now a query is { IdentifierStruct <booleanAnd/Or> }
Definition: TokenParser.cpp:57
int _identifierIndex
Definition: TokenParser.cpp:44
boolean stringIsQuery_mainModule(char *line)
whether the stirng is a potential query
struct identifierStruct IdentifierStruct
const int _identifierMaxLen
max length of an identifier..
Definition: TokenParser.cpp:40
TokensEnum _tokens[_tokensMax]
Definition: TokenParser.cpp:64
boolean nameMatchesWildcardQuery(char *name, IdentifierStruct idQueryStruct)
void addIdentifierChar(char c)
adds a valie character to an identifier
boolean _parsingIdentifier
whether in an identifier parsing
Definition: TokenParser.cpp:69
boolean queryMatchesName_mainModule(char *name)
void initIdentifier(char c)
initi for each new identifier
IdentifierStruct _identifierStructs[_identifierStructsMax]
array of identifiers ..
Definition: TokenParser.cpp:61
TokensEnum getToken(int num)
get the nth token
void parseQueryLine_mainModule(char *line)
parses a line of text, returning the number of tokens..
void setup_tokenParser_mainModule()
setup a test ..
void pushToken(TokensEnum token)
pushes token onto token stack
Definition: TokenParser.cpp:72
boolean validIdentifierChar(char c)
int numTokens()
how many tokens
void pushIdentifier(char *identifier)
pushes identifier onto identifier stack, while also inserting a token for identifier
char _sm_for_UUID_Flownum[100]
global for returning..
#define cmdIndex
char * getIdentifier(int num)
the nth identifier
const int _tokensMax
Definition: TokenParser.cpp:63
int _identifierStructsIndex
index into _identifiers array
Definition: TokenParser.cpp:59
#define smartSwitch
void processIdentifier()
int numIdentifiers()
how many identifiers
char * semanticMarkerToJSON_TokenParser(char *semanticMarker)
TokensEnum popTokenStack()
get the current top of stack token, and move the token stack pointer
Definition: TokenParser.cpp:95
int _tokensStackPointer
index into _tokens array
Definition: TokenParser.cpp:66
char _JSON_String_mainModule[300]
storage for the current identifier
char * parseSM_For_UUID_Flownum(char *semanticMarker)
void doneParsingIdentifier()
finished parsing an identifier
char _identifier[_identifierMaxLen]
storage for the current identifier
Definition: TokenParser.cpp:42
#define flagIndex
TokensEnum
retrieves the parsed values
Definition: TokenParser.cpp:30
@ identifier_enum
Definition: TokenParser.cpp:35
@ booleanOr_enum
Definition: TokenParser.cpp:33
@ notModifier_enum
Definition: TokenParser.cpp:31
@ booleanAnd_enum
Definition: TokenParser.cpp:34
@ wildcardAny_enum
Definition: TokenParser.cpp:32
@ null_enum
Definition: TokenParser.cpp:36
#define deviceIndex
IdentifierStruct getIdentifierStruct(int num)
grab full identifier struct (Pointer?)
#define setIndex
boolean wildcardAfter
Definition: TokenParser.cpp:50
boolean wildcardBefore
Definition: TokenParser.cpp:49
char identifier[_identifierMaxLen]
Definition: TokenParser.cpp:48