1450 |
|
|
1451 |
static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch); |
static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch); |
1452 |
|
|
1453 |
|
/** |
1454 |
|
* A set of parser symbol stacks. This type is used for the recursive algorithms |
1455 |
|
* in a) yyAutoComplete() and b) walkAndFillExpectedSymbols() for detecting |
1456 |
|
* endless recursions. |
1457 |
|
* |
1458 |
|
* This unique container is used to keep track of all previous parser states |
1459 |
|
* (stacks), for detecting a parser symbol stack that has already been |
1460 |
|
* encountered before. Because if yyAutoComplete() or |
1461 |
|
* walkAndFillExpectedSymbols() reach the exactly same parser symbol stack |
1462 |
|
* again, that means there is an endless recursion in that part of the grammar |
1463 |
|
* tree branch and shall not be evaluated any further, since it would end up in |
1464 |
|
* an endless loop of the algorithm otherwise. |
1465 |
|
* |
1466 |
|
* This solution consumes a lot of memory, but unfortunately there is no other |
1467 |
|
* easy way to solve it. With our grammar and today's usual memory heap size & |
1468 |
|
* memory stack size in modern devices, it should be fine though. |
1469 |
|
*/ |
1470 |
|
typedef std::set< std::vector<YYTYPE_INT16> > YYStackHistory; |
1471 |
|
|
1472 |
#define DEBUG_BISON_SYNTAX_ERROR_WALKER 0 |
#define DEBUG_BISON_SYNTAX_ERROR_WALKER 0 |
1473 |
|
|
1474 |
/** |
/** |
1491 |
* @param nextExpectedChars - just for internal purpose, due to the recursive |
* @param nextExpectedChars - just for internal purpose, due to the recursive |
1492 |
* implementation of this function, do supply an |
* implementation of this function, do supply an |
1493 |
* empty character for this argument |
* empty character for this argument |
1494 |
|
* @param history - only for internal purpose, keeps a history of all previous |
1495 |
|
* parser symbol stacks (just for avoiding endless recursion in |
1496 |
|
* this recursive algorithm) |
1497 |
* @param depth - just for internal debugging purposes |
* @param depth - just for internal debugging purposes |
1498 |
*/ |
*/ |
1499 |
static void walkAndFillExpectedSymbols( |
static void walkAndFillExpectedSymbols( |
1500 |
std::vector<YYTYPE_INT16>& stack, |
std::vector<YYTYPE_INT16>& stack, |
1501 |
std::map<String,BisonSymbolInfo>& expectedSymbols, |
std::map<String,BisonSymbolInfo>& expectedSymbols, |
1502 |
String& nextExpectedChars, int depth = 0) |
String& nextExpectedChars, YYStackHistory& history, int depth = 0) |
1503 |
{ |
{ |
1504 |
#if DEBUG_BISON_SYNTAX_ERROR_WALKER |
#if DEBUG_BISON_SYNTAX_ERROR_WALKER |
1505 |
printf("\n"); |
printf("\n"); |
1512 |
#endif |
#endif |
1513 |
startLabel: |
startLabel: |
1514 |
|
|
1515 |
|
// detect endless recursion |
1516 |
|
if (history.count(stack)) return; |
1517 |
|
history.insert(stack); |
1518 |
|
|
1519 |
if (stack.empty()) { |
if (stack.empty()) { |
1520 |
#if DEBUG_BISON_SYNTAX_ERROR_WALKER |
#if DEBUG_BISON_SYNTAX_ERROR_WALKER |
1521 |
for (int i = 0; i < depth; ++i) printf("\t"); |
for (int i = 0; i < depth; ++i) printf("\t"); |
1612 |
nextExpectedChars += _tokenName(token); |
nextExpectedChars += _tokenName(token); |
1613 |
nextExpectedCharsLen = nextExpectedChars.size(); |
nextExpectedCharsLen = nextExpectedChars.size(); |
1614 |
walkAndFillExpectedSymbols( //FIXME: could cause stack overflow (should be a loop instead), is probably fine with our current grammar though |
walkAndFillExpectedSymbols( //FIXME: could cause stack overflow (should be a loop instead), is probably fine with our current grammar though |
1615 |
stackCopy, expectedSymbols, nextExpectedChars, depth + 1 |
stackCopy, expectedSymbols, nextExpectedChars, history, depth + 1 |
1616 |
); |
); |
1617 |
nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars' |
nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars' |
1618 |
continue; |
continue; |
1658 |
stack.push_back(action); |
stack.push_back(action); |
1659 |
nextExpectedChars += _tokenName(token); |
nextExpectedChars += _tokenName(token); |
1660 |
walkAndFillExpectedSymbols( //FIXME: could cause stack overflow (should be a loop instead), is probably fine with our current grammar though |
walkAndFillExpectedSymbols( //FIXME: could cause stack overflow (should be a loop instead), is probably fine with our current grammar though |
1661 |
stack, expectedSymbols, nextExpectedChars, depth + 1 |
stack, expectedSymbols, nextExpectedChars, history, depth + 1 |
1662 |
); |
); |
1663 |
stack.resize(stackSize); // restore stack |
stack.resize(stackSize); // restore stack |
1664 |
nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars' |
nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars' |
1699 |
#endif |
#endif |
1700 |
} |
} |
1701 |
|
|
1702 |
|
/** |
1703 |
|
* Just a convenience wrapper on top of the actual walkAndFillExpectedSymbols() |
1704 |
|
* implementation above, which can be called with less parameters than the |
1705 |
|
* implementing function above actually requires. |
1706 |
|
*/ |
1707 |
|
static void walkAndFillExpectedSymbols( |
1708 |
|
std::vector<YYTYPE_INT16>& stack, |
1709 |
|
std::map<String,BisonSymbolInfo>& expectedSymbols) |
1710 |
|
{ |
1711 |
|
String nextExpectedChars; |
1712 |
|
YYStackHistory history; |
1713 |
|
|
1714 |
|
walkAndFillExpectedSymbols( |
1715 |
|
stack, expectedSymbols, nextExpectedChars, history |
1716 |
|
); |
1717 |
|
} |
1718 |
|
|
1719 |
#define DEBUG_PUSH_PARSE 0 |
#define DEBUG_PUSH_PARSE 0 |
1720 |
|
|
1721 |
/** |
/** |
1861 |
for (int i = 0; i < iStackSize; ++i) { |
for (int i = 0; i < iStackSize; ++i) { |
1862 |
stack.push_back(ss[i]); |
stack.push_back(ss[i]); |
1863 |
} |
} |
|
String notUsedHere; |
|
1864 |
// do the actual parser work |
// do the actual parser work |
1865 |
walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere); |
walkAndFillExpectedSymbols(stack, expectedSymbols); |
1866 |
|
|
1867 |
// convert expectedSymbols to the result set |
// convert expectedSymbols to the result set |
1868 |
std::set<String> result; |
std::set<String> result; |
1874 |
#define DEBUG_YY_AUTO_COMPLETE 0 |
#define DEBUG_YY_AUTO_COMPLETE 0 |
1875 |
|
|
1876 |
/** |
/** |
|
* A set of parser symbol stacks. This type is used in yyAutoComplete() to keep |
|
|
* track of all previous parser states, for detecting a parser symbol stack that |
|
|
* has already been before. Because if yyAutoComplete() reaches the exactly same |
|
|
* parser symbol stack again, it means there is an endless recursion in that |
|
|
* part of the grammar tree branch and shall not be evaluated any further, |
|
|
* because it would end up in an endless loop otherwise. |
|
|
* |
|
|
* This solution consumes a lot of memory, but unfortunately there is no other |
|
|
* easy way to solve it. With our grammar and today's memory heap size & memory |
|
|
* stack size it should be fine though. |
|
|
*/ |
|
|
typedef std::set< std::vector<YYTYPE_INT16> > YYStackHistory; |
|
|
|
|
|
/** |
|
1877 |
* Generates and returns an auto completion string for the current parser |
* Generates and returns an auto completion string for the current parser |
1878 |
* state given by @a stack. That means, this function will return the longest |
* state given by @a stack. That means, this function will return the longest |
1879 |
* sequence of characters that is uniqueley expected to be sent next by the LSCP |
* sequence of characters that is uniqueley expected to be sent next by the LSCP |
1902 |
*/ |
*/ |
1903 |
static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack, YYStackHistory& history, int depth = 0) { |
static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack, YYStackHistory& history, int depth = 0) { |
1904 |
std::map<String,BisonSymbolInfo> expectedSymbols; |
std::map<String,BisonSymbolInfo> expectedSymbols; |
1905 |
String notUsedHere; |
walkAndFillExpectedSymbols(stack, expectedSymbols); |
|
walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere); |
|
1906 |
if (expectedSymbols.size() == 1) { |
if (expectedSymbols.size() == 1) { |
1907 |
String name = expectedSymbols.begin()->first; |
String name = expectedSymbols.begin()->first; |
1908 |
BisonSymbolInfo info = expectedSymbols.begin()->second; |
BisonSymbolInfo info = expectedSymbols.begin()->second; |
2086 |
|
|
2087 |
// finally append all possible terminals and non-terminals according to |
// finally append all possible terminals and non-terminals according to |
2088 |
// current parser state |
// current parser state |
|
String notUsedHere; |
|
2089 |
std::map<String,BisonSymbolInfo> expectedSymbols; |
std::map<String,BisonSymbolInfo> expectedSymbols; |
2090 |
walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere); |
walkAndFillExpectedSymbols(stack, expectedSymbols); |
2091 |
{ |
{ |
2092 |
// pretend to LSCP shell that the following terminal symbols were |
// pretend to LSCP shell that the following terminal symbols were |
2093 |
// non-terminal symbols (since they are not human visible for auto |
// non-terminal symbols (since they are not human visible for auto |