67 |
return (c < 0); |
return (c < 0); |
68 |
} |
} |
69 |
|
|
70 |
|
// returns true if the given character is between between a to z. |
71 |
|
inline bool isLowerCaseAlphaChar(const char c) { |
72 |
|
return c >= 'a' && c <= 'z'; |
73 |
|
} |
74 |
|
|
75 |
|
// converts the given (expected) lower case character to upper case |
76 |
|
inline char alphaCharToUpperCase(const char c) { |
77 |
|
return (c - 'a') + 'A'; |
78 |
|
} |
79 |
|
|
80 |
// custom scanner function which reads from the socket |
// custom scanner function which reads from the socket |
81 |
// (bison expects it to return the numerical ID of the next |
// (bison expects it to return the numerical ID of the next |
82 |
// "recognized token" from the input stream) |
// "recognized token" from the input stream) |
440 |
| DB_INSTRUMENT SP FILE_PATH SP filename SP filename { $$ = LSCPSERVER->SetDbInstrumentFilePath($5,$7); } |
| DB_INSTRUMENT SP FILE_PATH SP filename SP filename { $$ = LSCPSERVER->SetDbInstrumentFilePath($5,$7); } |
441 |
| ECHO SP boolean { $$ = LSCPSERVER->SetEcho((yyparse_param_t*) yyparse_param, $3); } |
| ECHO SP boolean { $$ = LSCPSERVER->SetEcho((yyparse_param_t*) yyparse_param, $3); } |
442 |
| SHELL SP INTERACT SP boolean { $$ = LSCPSERVER->SetShellInteract((yyparse_param_t*) yyparse_param, $5); } |
| SHELL SP INTERACT SP boolean { $$ = LSCPSERVER->SetShellInteract((yyparse_param_t*) yyparse_param, $5); } |
443 |
|
| SHELL SP AUTO_CORRECT SP boolean { $$ = LSCPSERVER->SetShellAutoCorrect((yyparse_param_t*) yyparse_param, $5); } |
444 |
| VOLUME SP volume_value { $$ = LSCPSERVER->SetGlobalVolume($3); } |
| VOLUME SP volume_value { $$ = LSCPSERVER->SetGlobalVolume($3); } |
445 |
| VOICES SP number { $$ = LSCPSERVER->SetGlobalMaxVoices($3); } |
| VOICES SP number { $$ = LSCPSERVER->SetGlobalMaxVoices($3); } |
446 |
| STREAMS SP number { $$ = LSCPSERVER->SetGlobalMaxStreams($3); } |
| STREAMS SP number { $$ = LSCPSERVER->SetGlobalMaxStreams($3); } |
939 |
INTERACT : 'I''N''T''E''R''A''C''T' |
INTERACT : 'I''N''T''E''R''A''C''T' |
940 |
; |
; |
941 |
|
|
942 |
|
AUTO_CORRECT : 'A''U''T''O''_''C''O''R''R''E''C''T' |
943 |
|
; |
944 |
|
|
945 |
APPEND : 'A''P''P''E''N''D' |
APPEND : 'A''P''P''E''N''D' |
946 |
; |
; |
947 |
|
|
1283 |
|
|
1284 |
%% |
%% |
1285 |
|
|
1286 |
|
// TODO: actually would be fine to have the following bunch of source code in a separate file, however those functions are a) accessing private Bison tables like yytable and b) including the functions from another file here would make the line numbers incorrect on compile errors in auto generated lscpparser.cpp |
1287 |
|
|
1288 |
|
/** |
1289 |
|
* Additional informations of a grammar symbol. |
1290 |
|
*/ |
1291 |
|
struct BisonSymbolInfo { |
1292 |
|
bool isTerminalSymbol; ///< Whether the symbol is a terminal or non-termianl symbol. NOTE: Read comment regarding this in _isRuleTerminalSymbol() !! |
1293 |
|
String nextExpectedChars; ///< According to current parser position: sequence of characters expected next for satisfying this grammar symbol. |
1294 |
|
}; |
1295 |
|
|
1296 |
|
/** |
1297 |
|
* Returns true if the given grammar @a rule is a terminal symbol (in *our* |
1298 |
|
* terms). |
1299 |
|
* |
1300 |
|
* Please note that the term "terminal symbol" is a bit confusingly used in |
1301 |
|
* this source code here around. In Bison's terms, "terminal symbols" are (more |
1302 |
|
* or less) just the numbers returned by the YYLEX function. Since we decided |
1303 |
|
* though to use a convenient solution without a separate lexer, and all its |
1304 |
|
* caveats, all numbers by the yylex() function here are just the ASCII |
1305 |
|
* numbers of the individual characters received. Based on that however, one |
1306 |
|
* single character is not what one would intuitively expect of being a |
1307 |
|
* "terminal symbol", because it is simply too primitive. |
1308 |
|
* |
1309 |
|
* So in this LSCP parser source code a "terminal symbol" rather means a |
1310 |
|
* keyword like "CREATE" or "GET". In the grammal definition above, those are |
1311 |
|
* however defined as grammar rules (non-terminals in Bison's terms). So this |
1312 |
|
* function decides like this: if the given grammar rule just contains |
1313 |
|
* individual characters on the right side of its grammar rule, then it is a |
1314 |
|
* "terminal symbol" in *our* terms. |
1315 |
|
* |
1316 |
|
* @param rule - Bison grammar rule number |
1317 |
|
*/ |
1318 |
|
inline static bool _isRuleTerminalSymbol(int rule) { |
1319 |
|
for (int i = yyprhs[rule]; yyrhs[i] != -1; ++i) |
1320 |
|
if (yyrhs[i] >= YYNTOKENS) return false; |
1321 |
|
return true; |
1322 |
|
} |
1323 |
|
|
1324 |
|
/** |
1325 |
|
* Returns additional informations to the given grammar @a rule. |
1326 |
|
*/ |
1327 |
|
inline static BisonSymbolInfo _symbolInfoForRule(int rule, const String& nextExpectedChars) { |
1328 |
|
BisonSymbolInfo info; |
1329 |
|
info.isTerminalSymbol = _isRuleTerminalSymbol(rule); |
1330 |
|
if (info.isTerminalSymbol) info.nextExpectedChars = nextExpectedChars; |
1331 |
|
return info; |
1332 |
|
} |
1333 |
|
|
1334 |
|
/** |
1335 |
|
* Returns the human readable name of the given @a token. |
1336 |
|
*/ |
1337 |
|
inline static String _tokenName(int token) { |
1338 |
|
String s = yytname[token]; |
1339 |
|
// remove leading and trailing apostrophes that Bison usually adds to |
1340 |
|
// ASCII characters used directly in grammar rules |
1341 |
|
if (s.empty()) return s; |
1342 |
|
if (s[0] == '\'') s.erase(0, 1); |
1343 |
|
if (s.empty()) return s; |
1344 |
|
if (s[s.size() - 1] == '\'') s.erase(s.size() - 1); |
1345 |
|
return s; |
1346 |
|
} |
1347 |
|
|
1348 |
#define DEBUG_BISON_SYNTAX_ERROR_WALKER 0 |
#define DEBUG_BISON_SYNTAX_ERROR_WALKER 0 |
1349 |
|
|
1350 |
/** |
/** |
1351 |
* Internal function, only called by yyExpectedSymbols(). It is given a Bison |
* Tries to find the next expected grammar symbols according to the given |
1352 |
* parser state stack, reflecting the parser's entire state at a certain point, |
* precise parse position & state represented by @a stack, according to Bison's |
1353 |
* i.e. when a syntax error occured. This function will then walk ahead the |
* LALR(1) parser algorithm. |
|
* potential parse tree starting from the current head of the given state |
|
|
* stack. This function will call itself recursively to scan the individual |
|
|
* parse tree branches. As soon as it hits on the next non-terminal grammar |
|
|
* symbol in one parse tree branch, it adds the found non-terminal symbol to |
|
|
* @a expectedSymbols and aborts scanning the respective tree branch further. |
|
|
* If any local parser state is reached a second time, the respective parse |
|
|
* tree is aborted to avoid any endless recursion. |
|
1354 |
* |
* |
1355 |
* @param stack - Bison (yacc) state stack |
* This function is given a Bison parser state stack, reflecting the parser's |
1356 |
|
* entire state at a certain point, i.e. when a syntax error occured. This |
1357 |
|
* function will then walk ahead the potential parse tree starting from the |
1358 |
|
* current head of the given state stack. This function will call itself |
1359 |
|
* recursively to scan the individual parse tree branches. As soon as it hits |
1360 |
|
* on the next non-terminal grammar symbol in one parse tree branch, it adds the |
1361 |
|
* found non-terminal symbol to @a expectedSymbols and aborts scanning the |
1362 |
|
* respective tree branch further. If any local parser state is reached a second |
1363 |
|
* time, the respective parse tree is aborted to avoid any endless recursion. |
1364 |
|
* |
1365 |
|
* @param stack - current Bison (yacc) state stack to be examined |
1366 |
* @param expectedSymbols - will be filled with next expected grammar symbols |
* @param expectedSymbols - will be filled with next expected grammar symbols |
1367 |
|
* @param nextExpectedChars - just for internal purpose, due to the recursive |
1368 |
|
* implementation of this function, do supply an |
1369 |
|
* empty character for this argument |
1370 |
* @param depth - just for internal debugging purposes |
* @param depth - just for internal debugging purposes |
1371 |
*/ |
*/ |
1372 |
static void walkAndFillExpectedSymbols(std::vector<YYTYPE_INT16>& stack, std::set<String>& expectedSymbols, int depth = 0) { |
static void walkAndFillExpectedSymbols( |
1373 |
|
std::vector<YYTYPE_INT16>& stack, |
1374 |
|
std::map<String,BisonSymbolInfo>& expectedSymbols, |
1375 |
|
String& nextExpectedChars, int depth = 0) |
1376 |
|
{ |
1377 |
#if DEBUG_BISON_SYNTAX_ERROR_WALKER |
#if DEBUG_BISON_SYNTAX_ERROR_WALKER |
1378 |
printf("\n"); |
printf("\n"); |
1379 |
for (int i = 0; i < depth; ++i) printf("\t"); |
for (int i = 0; i < depth; ++i) printf("\t"); |
1394 |
if (n <= 0 || n >= YYNRULES) return; // no rule, something is wrong |
if (n <= 0 || n >= YYNRULES) return; // no rule, something is wrong |
1395 |
// return the new resolved expected symbol (left-hand symbol of grammar |
// return the new resolved expected symbol (left-hand symbol of grammar |
1396 |
// rule), then we're done in this state |
// rule), then we're done in this state |
1397 |
expectedSymbols.insert(yytname[yyr1[n]]); |
expectedSymbols[yytname[yyr1[n]]] = _symbolInfoForRule(n, nextExpectedChars); |
1398 |
return; |
return; |
1399 |
} |
} |
1400 |
if (!(YYPACT_NINF < n && n <= YYLAST)) return; |
if (!(YYPACT_NINF < n && n <= YYLAST)) return; |
1406 |
int begin = n < 0 ? -n : 0; |
int begin = n < 0 ? -n : 0; |
1407 |
int checklim = YYLAST - n + 1; |
int checklim = YYLAST - n + 1; |
1408 |
int end = checklim < YYNTOKENS ? checklim : YYNTOKENS; |
int end = checklim < YYNTOKENS ? checklim : YYNTOKENS; |
1409 |
int rule, action, stackSize; |
int rule, action, stackSize, nextExpectedCharsLen; |
1410 |
for (int token = begin; token < end; ++token) { |
for (int token = begin; token < end; ++token) { |
1411 |
if (token == YYTERROR || yycheck[n + token] != token) continue; |
if (token == YYTERROR || yycheck[n + token] != token) continue; |
1412 |
#if DEBUG_BISON_SYNTAX_ERROR_WALKER |
#if DEBUG_BISON_SYNTAX_ERROR_WALKER |
1439 |
// "shift" / push the new state on the state stack and call this |
// "shift" / push the new state on the state stack and call this |
1440 |
// function recursively, and restore the stack after the recurse return |
// function recursively, and restore the stack after the recurse return |
1441 |
stackSize = stack.size(); |
stackSize = stack.size(); |
1442 |
|
nextExpectedCharsLen = nextExpectedChars.size(); |
1443 |
stack.push_back(action); |
stack.push_back(action); |
1444 |
|
nextExpectedChars += _tokenName(token); |
1445 |
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 |
1446 |
stack, expectedSymbols, depth + 1 |
stack, expectedSymbols, nextExpectedChars, depth + 1 |
1447 |
); |
); |
1448 |
stack.resize(stackSize); // restore stack |
stack.resize(stackSize); // restore stack |
1449 |
|
nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars' |
1450 |
continue; |
continue; |
1451 |
|
|
1452 |
//default_reduction: // resolve default reduction for this state |
//default_reduction: // resolve default reduction for this state |
1459 |
#endif |
#endif |
1460 |
if (rule == 0 || rule >= YYNRULES) continue; // invalid rule, something is wrong |
if (rule == 0 || rule >= YYNRULES) continue; // invalid rule, something is wrong |
1461 |
// store the left-hand symbol of the grammar rule |
// store the left-hand symbol of the grammar rule |
1462 |
expectedSymbols.insert(yytname[yyr1[rule]]); |
expectedSymbols[yytname[yyr1[rule]]] = _symbolInfoForRule(rule, nextExpectedChars); |
1463 |
#if DEBUG_BISON_SYNTAX_ERROR_WALKER |
#if DEBUG_BISON_SYNTAX_ERROR_WALKER |
1464 |
printf(" (SYM %s) ", yytname[yyr1[rule]]); fflush(stdout); |
printf(" (SYM %s) ", yytname[yyr1[rule]]); fflush(stdout); |
1465 |
#endif |
#endif |
1469 |
#endif |
#endif |
1470 |
} |
} |
1471 |
|
|
1472 |
|
/** |
1473 |
|
* Implements Bison's so called "reduce" action, according to Bison's LALR(1) |
1474 |
|
* parser algorithm. |
1475 |
|
*/ |
1476 |
inline static int _yyReduce(std::vector<YYTYPE_INT16>& stack, const int& rule) { |
inline static int _yyReduce(std::vector<YYTYPE_INT16>& stack, const int& rule) { |
1477 |
if (stack.empty()) throw 1; // severe error |
if (stack.empty()) throw 1; // severe error |
1478 |
const int len = yyr2[rule]; |
const int len = yyr2[rule]; |
1486 |
return newState; |
return newState; |
1487 |
} |
} |
1488 |
|
|
1489 |
|
/** |
1490 |
|
* Implements Bison's so called "default reduce" action, according to Bison's |
1491 |
|
* LALR(1) parser algorithm. |
1492 |
|
*/ |
1493 |
inline static int _yyDefaultReduce(std::vector<YYTYPE_INT16>& stack) { |
inline static int _yyDefaultReduce(std::vector<YYTYPE_INT16>& stack) { |
1494 |
if (stack.empty()) throw 2; // severe error |
if (stack.empty()) throw 2; // severe error |
1495 |
int rule = yydefact[stack.back()]; |
int rule = yydefact[stack.back()]; |
1499 |
|
|
1500 |
#define DEBUG_PUSH_PARSE 0 |
#define DEBUG_PUSH_PARSE 0 |
1501 |
|
|
1502 |
|
/** |
1503 |
|
* Implements parsing exactly one character (given by @a c), continueing at the |
1504 |
|
* parser position reflected by @a stack. The @a stack will hold the new parser |
1505 |
|
* state after this call. |
1506 |
|
* |
1507 |
|
* This function is implemented according to Bison's LALR(1) parser algorithm. |
1508 |
|
*/ |
1509 |
static bool yyPushParse(std::vector<YYTYPE_INT16>& stack, char ch) { |
static bool yyPushParse(std::vector<YYTYPE_INT16>& stack, char ch) { |
1510 |
startLabel: |
startLabel: |
1511 |
|
|
1562 |
return true; |
return true; |
1563 |
} |
} |
1564 |
|
|
1565 |
|
/** |
1566 |
|
* Returns true if parsing ahead with given character @a ch is syntactially |
1567 |
|
* valid according to the LSCP grammar, it returns false if it would create a |
1568 |
|
* parse error. |
1569 |
|
* |
1570 |
|
* This is just a wrapper ontop of yyPushParse() which converts parser |
1571 |
|
* exceptions thrown by yyPushParse() into negative return value. |
1572 |
|
*/ |
1573 |
static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch) { |
static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch) { |
1574 |
try { |
try { |
1575 |
return yyPushParse(stack, ch); |
return yyPushParse(stack, ch); |
1583 |
} |
} |
1584 |
} |
} |
1585 |
|
|
1586 |
static int yyValidCharacters(std::vector<YYTYPE_INT16>& stack, const String& line) { |
/** |
1587 |
|
* Returns the amount of correct characters of given @a line from the left, |
1588 |
|
* according to the LSCP grammar. |
1589 |
|
* |
1590 |
|
* @param stack - a Bison symbol state stack to work with |
1591 |
|
* @param line - the input line to check |
1592 |
|
* @param bAutoCorrect - if true: try to correct obvious, trivial syntax errors |
1593 |
|
*/ |
1594 |
|
static int yyValidCharacters(std::vector<YYTYPE_INT16>& stack, String& line, bool bAutoCorrect) { |
1595 |
int i; |
int i; |
1596 |
for (i = 0; i < line.size(); ++i) { |
for (i = 0; i < line.size(); ++i) { |
1597 |
if (!yyValid(stack, line[i])) return i; |
// since we might check the same parser state twice against the current |
1598 |
|
// char here below, and since the state stack might be altered |
1599 |
|
// (i.e. shifted or reduced) on syntax errors, we have to backup the |
1600 |
|
// current state stack and restore it on syntax errors below |
1601 |
|
std::vector<YYTYPE_INT16> stackBackup = stack; |
1602 |
|
if (yyValid(stackBackup, line[i])) { |
1603 |
|
stack = stackBackup; |
1604 |
|
continue; |
1605 |
|
} |
1606 |
|
if (bAutoCorrect) { |
1607 |
|
// try trivial corrections, i.e. upper case character instead of |
1608 |
|
// lower case, subline instead of space and vice versa |
1609 |
|
char c; |
1610 |
|
if (line[i] == ' ') c = '_'; |
1611 |
|
else if (line[i] == '_') c = ' '; |
1612 |
|
else if (isLowerCaseAlphaChar(line[i])) |
1613 |
|
c = alphaCharToUpperCase(line[i]); |
1614 |
|
else return i; |
1615 |
|
if (yyValid(stack, c)) { |
1616 |
|
line[i] = c; |
1617 |
|
continue; |
1618 |
|
} |
1619 |
|
} |
1620 |
|
return i; |
1621 |
} |
} |
1622 |
return i; |
return i; |
1623 |
} |
} |
1628 |
* error appeared. |
* error appeared. |
1629 |
*/ |
*/ |
1630 |
static std::set<String> yyExpectedSymbols() { |
static std::set<String> yyExpectedSymbols() { |
1631 |
std::set<String> result; |
std::map<String,BisonSymbolInfo> expectedSymbols; |
1632 |
yyparse_param_t* param = GetCurrentYaccSession(); |
yyparse_param_t* param = GetCurrentYaccSession(); |
1633 |
YYTYPE_INT16* ss = (*param->ppStackBottom); |
YYTYPE_INT16* ss = (*param->ppStackBottom); |
1634 |
YYTYPE_INT16* sp = (*param->ppStackTop); |
YYTYPE_INT16* sp = (*param->ppStackTop); |
1638 |
for (int i = 0; i < iStackSize; ++i) { |
for (int i = 0; i < iStackSize; ++i) { |
1639 |
stack.push_back(ss[i]); |
stack.push_back(ss[i]); |
1640 |
} |
} |
1641 |
|
String notUsedHere; |
1642 |
// do the actual parser work |
// do the actual parser work |
1643 |
walkAndFillExpectedSymbols(stack, result); |
walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere); |
1644 |
|
|
1645 |
|
// convert expectedSymbols to the result set |
1646 |
|
std::set<String> result; |
1647 |
|
for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin(); |
1648 |
|
it != expectedSymbols.end(); ++it) result.insert(it->first); |
1649 |
return result; |
return result; |
1650 |
} |
} |
1651 |
|
|
1652 |
namespace LinuxSampler { |
namespace LinuxSampler { |
1653 |
|
|
1654 |
|
#define DEBUG_SHELL_INTERACTION 0 |
1655 |
|
|
1656 |
|
/** |
1657 |
|
* If LSP shell mode is enabled, then this function is called on every new |
1658 |
|
* received from client. It will check the current total input line and reply |
1659 |
|
* to the LSCP shell for providing colored syntax highlighting and potential |
1660 |
|
* auto completion in the shell. |
1661 |
|
* |
1662 |
|
* It also performs auto correction of obvious & trivial syntax mistakes if |
1663 |
|
* requested. |
1664 |
|
*/ |
1665 |
String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param) { |
String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param) { |
1666 |
|
// first, determine how many characters (starting from the left) of the |
1667 |
|
// given input line are already syntactially correct |
1668 |
std::vector<YYTYPE_INT16> stack; |
std::vector<YYTYPE_INT16> stack; |
1669 |
stack.push_back(0); // every Bison symbol stack starts with zero |
stack.push_back(0); // every Bison symbol stack starts with state zero |
1670 |
String l = line + '\n'; |
String l = line + '\n'; // '\n' to pretend ENTER as if the line was now complete |
1671 |
int n = yyValidCharacters(stack, l); |
int n = yyValidCharacters(stack, l, param->bShellAutoCorrect); |
1672 |
|
|
1673 |
|
// if auto correction is enabled, apply the auto corrected string to |
1674 |
|
// intput/output string 'line' |
1675 |
|
if (param->bShellAutoCorrect) { |
1676 |
|
int nMin = (n < line.length()) ? n : line.length(); |
1677 |
|
line.replace(0, nMin, l.substr(0, nMin)); |
1678 |
|
} |
1679 |
|
|
1680 |
|
// generate an info string that will be sent to the LSCP shell for letting |
1681 |
|
// it know which part is correct, which one is wrong, where is the cursor, etc. |
1682 |
String result = line; |
String result = line; |
1683 |
result.insert(n <= result.length() ? n : result.length(), LSCP_SHK_GOOD_FRONT); |
result.insert(n <= result.length() ? n : result.length(), LSCP_SHK_GOOD_FRONT); |
1684 |
int code = (n > line.length()) ? LSCP_SHU_COMPLETE : (n < line.length()) ? |
int code = (n > line.length()) ? LSCP_SHU_COMPLETE : (n < line.length()) ? |
1685 |
LSCP_SHU_SYNTAX_ERR : LSCP_SHU_INCOMPLETE; |
LSCP_SHU_SYNTAX_ERR : LSCP_SHU_INCOMPLETE; |
1686 |
result = "SHU:" + ToString(code) + ":" + result; |
result = "SHU:" + ToString(code) + ":" + result + LSCP_SHK_CURSOR; |
1687 |
//if (n > line.length()) result += " [OK]"; |
//if (n > line.length()) result += " [OK]"; |
1688 |
#if DEBUG_PUSH_PARSE |
|
1689 |
|
// get a clean parser stack to the last valid parse position |
1690 |
|
// (due to the appended '\n' character above, and on syntax errors, the |
1691 |
|
// state stack might be in undesired, i.e. reduced state) |
1692 |
|
stack.clear(); |
1693 |
|
stack.push_back(0); // every Bison symbol stack starts with state zero |
1694 |
|
l = line.substr(0, n); |
1695 |
|
if (!l.empty()) yyValidCharacters(stack, l, param->bShellAutoCorrect); |
1696 |
|
|
1697 |
|
// generate auto completion suggestion (based on the current parser stack) |
1698 |
|
std::map<String,BisonSymbolInfo> expectedSymbols; |
1699 |
|
String notUsedHere; |
1700 |
|
walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere); |
1701 |
|
if (expectedSymbols.size() == 1) { |
1702 |
|
String name = expectedSymbols.begin()->first; |
1703 |
|
BisonSymbolInfo info = expectedSymbols.begin()->second; |
1704 |
|
#if DEBUG_SHELL_INTERACTION |
1705 |
|
printf("Suggested Completion (%d): %s '%s'\n", expectedSymbols.size(), (info.isTerminalSymbol) ? "T:" : "NT:", (name + " (" + info.nextExpectedChars + ")").c_str()); |
1706 |
|
#endif |
1707 |
|
result += LSCP_SHK_SUGGEST_BACK + info.nextExpectedChars; |
1708 |
|
} else if (expectedSymbols.size() == 0) { |
1709 |
|
#if DEBUG_SHELL_INTERACTION |
1710 |
|
printf("No suggestion.\n"); |
1711 |
|
#endif |
1712 |
|
} else if (expectedSymbols.size() > 1) { |
1713 |
|
#if DEBUG_SHELL_INTERACTION |
1714 |
|
printf("Multiple possibilities:"); |
1715 |
|
for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin(); |
1716 |
|
it != expectedSymbols.end(); ++it) |
1717 |
|
{ |
1718 |
|
printf(" %s (..%s)", it->first.c_str(), it->second.nextExpectedChars.c_str()); |
1719 |
|
} |
1720 |
|
printf("\n"); |
1721 |
|
#endif |
1722 |
|
// check if any of the possibilites is a non-terminal symbol, if so, we |
1723 |
|
// have no way for auto completion at this point |
1724 |
|
bool bNonTerminalExists = false; |
1725 |
|
for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin(); |
1726 |
|
it != expectedSymbols.end(); ++it) if (!it->second.isTerminalSymbol) { bNonTerminalExists = true; break; }; |
1727 |
|
if (!bNonTerminalExists) { |
1728 |
|
// all possibilites are terminal symbaols, so try to find the least |
1729 |
|
// common string all possibilites start with from the left |
1730 |
|
String sCommon; |
1731 |
|
for (int i = 0; true; ++i) { |
1732 |
|
char c; |
1733 |
|
for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin(); |
1734 |
|
it != expectedSymbols.end(); ++it) |
1735 |
|
{ |
1736 |
|
if (i >= it->second.nextExpectedChars.size()) |
1737 |
|
goto commonSearchEndLabel; |
1738 |
|
if (it == expectedSymbols.begin()) |
1739 |
|
c = it->second.nextExpectedChars[i]; |
1740 |
|
if (c != it->second.nextExpectedChars[i]) |
1741 |
|
goto commonSearchEndLabel; |
1742 |
|
if (it == --expectedSymbols.end()) |
1743 |
|
sCommon += c; |
1744 |
|
} |
1745 |
|
} |
1746 |
|
commonSearchEndLabel: |
1747 |
|
if (!sCommon.empty()) result += LSCP_SHK_SUGGEST_BACK + sCommon; |
1748 |
|
#if DEBUG_SHELL_INTERACTION |
1749 |
|
printf("Common possibility: '%s'\n", sCommon.c_str()); |
1750 |
|
#endif |
1751 |
|
} |
1752 |
|
} |
1753 |
|
|
1754 |
|
#if DEBUG_SHELL_INTERACTION |
1755 |
printf("%s\n", result.c_str()); |
printf("%s\n", result.c_str()); |
1756 |
#endif |
#endif |
1757 |
|
|
1758 |
return result; |
return result; |
1759 |
} |
} |
1760 |
|
|