/[svn]/linuxsampler/trunk/src/network/lscp.y
ViewVC logotype

Diff of /linuxsampler/trunk/src/network/lscp.y

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2515 by schoenebeck, Wed Feb 5 20:45:18 2014 UTC revision 2516 by schoenebeck, Thu Feb 6 21:11:23 2014 UTC
# Line 67  inline bool isExtendedAsciiChar(const ch Line 67  inline bool isExtendedAsciiChar(const ch
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)
# Line 430  set_instruction       :  AUDIO_OUTPUT_DE Line 440  set_instruction       :  AUDIO_OUTPUT_DE
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);                        }
# Line 928  SHELL                 :  'S''H''E''L''L' Line 939  SHELL                 :  'S''H''E''L''L'
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    
# Line 1269  QUIT                  :  'Q''U''I''T' Line 1283  QUIT                  :  'Q''U''I''T'
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");
# Line 1308  static void walkAndFillExpectedSymbols(s Line 1394  static void walkAndFillExpectedSymbols(s
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;
# Line 1320  static void walkAndFillExpectedSymbols(s Line 1406  static void walkAndFillExpectedSymbols(s
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
# Line 1353  static void walkAndFillExpectedSymbols(s Line 1439  static void walkAndFillExpectedSymbols(s
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
# Line 1370  static void walkAndFillExpectedSymbols(s Line 1459  static void walkAndFillExpectedSymbols(s
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
# Line 1380  static void walkAndFillExpectedSymbols(s Line 1469  static void walkAndFillExpectedSymbols(s
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];
# Line 1393  inline static int _yyReduce(std::vector< Line 1486  inline static int _yyReduce(std::vector<
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()];
# Line 1402  inline static int _yyDefaultReduce(std:: Line 1499  inline static int _yyDefaultReduce(std::
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    
# Line 1458  static bool yyPushParse(std::vector<YYTY Line 1562  static bool yyPushParse(std::vector<YYTY
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);
# Line 1471  static bool yyValid(std::vector<YYTYPE_I Line 1583  static bool yyValid(std::vector<YYTYPE_I
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  }  }
# Line 1485  static int yyValidCharacters(std::vector Line 1628  static int yyValidCharacters(std::vector
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);
# Line 1495  static std::set<String> yyExpectedSymbol Line 1638  static std::set<String> yyExpectedSymbol
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    

Legend:
Removed from v.2515  
changed lines
  Added in v.2516

  ViewVC Help
Powered by ViewVC