/[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 2518 by schoenebeck, Sat Feb 8 00:49:30 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    #if HAVE_BISON_MAJ >= 3 // Bison 3.x or younger ...
1297    
1298    /**
1299     * Must ONLY be called just before a so called "reduce" parser action:
1300     * Returns true if the grammar rule, which is just about to be "reduced", is a
1301     * terminal symbol (in *our* terms).
1302     *
1303     * Please note that the term "terminal symbol" is a bit confusingly used in
1304     * this source code here around. In Bison's terms, "terminal symbols" are (more
1305     * or less) just the numbers returned by the YYLEX function. Since we decided
1306     * though to use a convenient solution without a separate lexer, and all its
1307     * caveats, all numbers by the yylex() function here are just the ASCII
1308     * numbers of the individual characters received. Based on that however, one
1309     * single character is not what one would intuitively expect of being a
1310     * "terminal symbol", because it is simply too primitive.
1311     *
1312     * So in this LSCP parser source code a "terminal symbol" rather means a
1313     * keyword like "CREATE" or "GET". In the grammal definition above, those are
1314     * however defined as grammar rules (non-terminals in Bison's terms). So this
1315     * function decides like this: if the given grammar rule just contains
1316     * individual characters on the right side of its grammar rule, then it is a
1317     * "terminal symbol" in *our* terms.
1318     *
1319     * @param rule - Bison grammar rule number
1320     * @param stack - reflecting current Bison parser state
1321     */
1322    inline static bool _isRuleTerminalSymbol(int rule, const std::vector<YYTYPE_INT16>& stack) {
1323        int nrhs = yyr2[rule];
1324        for (int i = 0; i < nrhs; ++i)
1325            if (yystos[*(stack.end() - nrhs + i)] >= YYNTOKENS) return false;
1326        return true;
1327    }
1328    
1329    /**
1330     * Must ONLY be called just before a so called "reduce" parser action: Returns
1331     * additional informations to the given grammar rule that is about to be
1332     * "reduced".
1333     *
1334     * @param rule - Bison grammar rule number
1335     * @param stack - reflecting current Bison parser state
1336     * @param nextExpectedChars - must already be filled with the characters
1337     *                            expected to be coming next
1338     */
1339    inline static BisonSymbolInfo _symbolInfoForRule(int rule, const std::vector<YYTYPE_INT16>& stack, const String& nextExpectedChars) {
1340        BisonSymbolInfo info;
1341        info.isTerminalSymbol = _isRuleTerminalSymbol(rule, stack);
1342        if (info.isTerminalSymbol) info.nextExpectedChars  = nextExpectedChars;
1343        return info;
1344    }
1345    
1346    #else // Bison 2.x or older ...
1347    
1348    /**
1349     * Returns true if the given grammar @a rule is a terminal symbol (in *our*
1350     * terms).
1351     *
1352     * Please note that the term "terminal symbol" is a bit confusingly used in
1353     * this source code here around. In Bison's terms, "terminal symbols" are (more
1354     * or less) just the numbers returned by the YYLEX function. Since we decided
1355     * though to use a convenient solution without a separate lexer, and all its
1356     * caveats, all numbers by the yylex() function here are just the ASCII
1357     * numbers of the individual characters received. Based on that however, one
1358     * single character is not what one would intuitively expect of being a
1359     * "terminal symbol", because it is simply too primitive.
1360     *
1361     * So in this LSCP parser source code a "terminal symbol" rather means a
1362     * keyword like "CREATE" or "GET". In the grammal definition above, those are
1363     * however defined as grammar rules (non-terminals in Bison's terms). So this
1364     * function decides like this: if the given grammar rule just contains
1365     * individual characters on the right side of its grammar rule, then it is a
1366     * "terminal symbol" in *our* terms.
1367     *
1368     * @param rule - Bison grammar rule number
1369     */
1370    inline static bool _isRuleTerminalSymbol(int rule) {
1371        for (int i = yyprhs[rule]; yyrhs[i] != -1; ++i)
1372            if (yyrhs[i] >= YYNTOKENS) return false;
1373        return true;
1374    }
1375    
1376    /**
1377     * Returns additional informations to the given grammar @a rule.
1378     *
1379     * @param rule - grammar rule index to retrieve informations about
1380     * @param nextExpectedChars - must already be filled with the characters
1381     *                            expected to be coming next
1382     */
1383    inline static BisonSymbolInfo _symbolInfoForRule(int rule, const String& nextExpectedChars) {
1384        BisonSymbolInfo info;
1385        info.isTerminalSymbol = _isRuleTerminalSymbol(rule);
1386        if (info.isTerminalSymbol) info.nextExpectedChars  = nextExpectedChars;
1387        return info;
1388    }
1389    
1390    #endif // HAVE_BISON_MAJ >= 3
1391    
1392    /**
1393     * Returns the human readable name of the given @a token.
1394     */
1395    inline static String _tokenName(int token) {
1396        String s = yytname[token];
1397        // remove leading and trailing apostrophes that Bison usually adds to
1398        // ASCII characters used directly in grammar rules
1399        if (s.empty()) return s;
1400        if (s[0] == '\'') s.erase(0, 1);
1401        if (s.empty()) return s;
1402        if (s[s.size() - 1] == '\'') s.erase(s.size() - 1);
1403        return s;
1404    }
1405    
1406  #define DEBUG_BISON_SYNTAX_ERROR_WALKER 0  #define DEBUG_BISON_SYNTAX_ERROR_WALKER 0
1407    
1408  /**  /**
1409   * Internal function, only called by yyExpectedSymbols(). It is given a Bison   * Tries to find the next expected grammar symbols according to the given
1410   * 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
1411   * 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.  
1412   *   *
1413   * @param stack - Bison (yacc) state stack   * This function is given a Bison parser state stack, reflecting the parser's
1414     * entire state at a certain point, i.e. when a syntax error occured. This
1415     * function will then walk ahead the potential parse tree starting from the
1416     * current head of the given state stack. This function will call itself
1417     * recursively to scan the individual parse tree branches. As soon as it hits
1418     * on the next non-terminal grammar symbol in one parse tree branch, it adds the
1419     * found non-terminal symbol to @a expectedSymbols and aborts scanning the
1420     * respective tree branch further. If any local parser state is reached a second
1421     * time, the respective parse tree is aborted to avoid any endless recursion.
1422     *
1423     * @param stack - current Bison (yacc) state stack to be examined
1424   * @param expectedSymbols - will be filled with next expected grammar symbols   * @param expectedSymbols - will be filled with next expected grammar symbols
1425     * @param nextExpectedChars - just for internal purpose, due to the recursive
1426     *                            implementation of this function, do supply an
1427     *                            empty character for this argument
1428   * @param depth - just for internal debugging purposes   * @param depth - just for internal debugging purposes
1429   */   */
1430  static void walkAndFillExpectedSymbols(std::vector<YYTYPE_INT16>& stack, std::set<String>& expectedSymbols, int depth = 0) {  static void walkAndFillExpectedSymbols(
1431        std::vector<YYTYPE_INT16>& stack,
1432        std::map<String,BisonSymbolInfo>& expectedSymbols,
1433        String& nextExpectedChars, int depth = 0)
1434    {
1435  #if DEBUG_BISON_SYNTAX_ERROR_WALKER  #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1436      printf("\n");      printf("\n");
1437      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 1452  static void walkAndFillExpectedSymbols(s
1452          if (n <= 0 || n >= YYNRULES) return; // no rule, something is wrong          if (n <= 0 || n >= YYNRULES) return; // no rule, something is wrong
1453          // return the new resolved expected symbol (left-hand symbol of grammar          // return the new resolved expected symbol (left-hand symbol of grammar
1454          // rule), then we're done in this state          // rule), then we're done in this state
1455          expectedSymbols.insert(yytname[yyr1[n]]);          #if HAVE_BISON_MAJ >= 3
1456            expectedSymbols[yytname[yyr1[n]]] = _symbolInfoForRule(n, stack, nextExpectedChars);
1457            #else
1458            expectedSymbols[yytname[yyr1[n]]] = _symbolInfoForRule(n, nextExpectedChars);
1459            #endif
1460          return;          return;
1461      }      }
1462      if (!(YYPACT_NINF < n && n <= YYLAST)) return;      if (!(YYPACT_NINF < n && n <= YYLAST)) return;
# Line 1320  static void walkAndFillExpectedSymbols(s Line 1468  static void walkAndFillExpectedSymbols(s
1468      int begin = n < 0 ? -n : 0;      int begin = n < 0 ? -n : 0;
1469      int checklim = YYLAST - n + 1;      int checklim = YYLAST - n + 1;
1470      int end = checklim < YYNTOKENS ? checklim : YYNTOKENS;      int end = checklim < YYNTOKENS ? checklim : YYNTOKENS;
1471      int rule, action, stackSize;      int rule, action, stackSize, nextExpectedCharsLen;
1472      for (int token = begin; token < end; ++token) {      for (int token = begin; token < end; ++token) {
1473          if (token == YYTERROR || yycheck[n + token] != token) continue;          if (token == YYTERROR || yycheck[n + token] != token) continue;
1474  #if DEBUG_BISON_SYNTAX_ERROR_WALKER  #if DEBUG_BISON_SYNTAX_ERROR_WALKER
# Line 1353  static void walkAndFillExpectedSymbols(s Line 1501  static void walkAndFillExpectedSymbols(s
1501          // "shift" / push the new state on the state stack and call this          // "shift" / push the new state on the state stack and call this
1502          // function recursively, and restore the stack after the recurse return          // function recursively, and restore the stack after the recurse return
1503          stackSize = stack.size();          stackSize = stack.size();
1504            nextExpectedCharsLen = nextExpectedChars.size();
1505          stack.push_back(action);          stack.push_back(action);
1506            nextExpectedChars += _tokenName(token);
1507          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
1508              stack, expectedSymbols, depth + 1              stack, expectedSymbols, nextExpectedChars, depth + 1
1509          );          );
1510          stack.resize(stackSize); // restore stack          stack.resize(stackSize); // restore stack
1511            nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'
1512          continue;          continue;
1513    
1514      //default_reduction: // resolve default reduction for this state      //default_reduction: // resolve default reduction for this state
# Line 1370  static void walkAndFillExpectedSymbols(s Line 1521  static void walkAndFillExpectedSymbols(s
1521  #endif  #endif
1522          if (rule == 0 || rule >= YYNRULES) continue; // invalid rule, something is wrong          if (rule == 0 || rule >= YYNRULES) continue; // invalid rule, something is wrong
1523          // store the left-hand symbol of the grammar rule          // store the left-hand symbol of the grammar rule
1524          expectedSymbols.insert(yytname[yyr1[rule]]);          #if HAVE_BISON_MAJ >= 3
1525            expectedSymbols[yytname[yyr1[rule]]] = _symbolInfoForRule(rule, stack, nextExpectedChars);
1526            #else
1527            expectedSymbols[yytname[yyr1[rule]]] = _symbolInfoForRule(rule, nextExpectedChars);
1528            #endif
1529  #if DEBUG_BISON_SYNTAX_ERROR_WALKER  #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1530          printf(" (SYM %s) ", yytname[yyr1[rule]]); fflush(stdout);          printf(" (SYM %s) ", yytname[yyr1[rule]]); fflush(stdout);
1531  #endif  #endif
# Line 1380  static void walkAndFillExpectedSymbols(s Line 1535  static void walkAndFillExpectedSymbols(s
1535  #endif  #endif
1536  }  }
1537    
1538    /**
1539     * Implements Bison's so called "reduce" action, according to Bison's LALR(1)
1540     * parser algorithm.
1541     */
1542  inline static int _yyReduce(std::vector<YYTYPE_INT16>& stack, const int& rule) {  inline static int _yyReduce(std::vector<YYTYPE_INT16>& stack, const int& rule) {
1543      if (stack.empty()) throw 1; // severe error      if (stack.empty()) throw 1; // severe error
1544      const int len = yyr2[rule];      const int len = yyr2[rule];
# Line 1393  inline static int _yyReduce(std::vector< Line 1552  inline static int _yyReduce(std::vector<
1552      return newState;      return newState;
1553  }  }
1554    
1555    /**
1556     * Implements Bison's so called "default reduce" action, according to Bison's
1557     * LALR(1) parser algorithm.
1558     */
1559  inline static int _yyDefaultReduce(std::vector<YYTYPE_INT16>& stack) {  inline static int _yyDefaultReduce(std::vector<YYTYPE_INT16>& stack) {
1560      if (stack.empty()) throw 2; // severe error      if (stack.empty()) throw 2; // severe error
1561      int rule = yydefact[stack.back()];      int rule = yydefact[stack.back()];
# Line 1402  inline static int _yyDefaultReduce(std:: Line 1565  inline static int _yyDefaultReduce(std::
1565    
1566  #define DEBUG_PUSH_PARSE 0  #define DEBUG_PUSH_PARSE 0
1567    
1568    /**
1569     * Implements parsing exactly one character (given by @a c), continueing at the
1570     * parser position reflected by @a stack. The @a stack will hold the new parser
1571     * state after this call.
1572     *
1573     * This function is implemented according to Bison's LALR(1) parser algorithm.
1574     */
1575  static bool yyPushParse(std::vector<YYTYPE_INT16>& stack, char ch) {  static bool yyPushParse(std::vector<YYTYPE_INT16>& stack, char ch) {
1576      startLabel:      startLabel:
1577    
# Line 1458  static bool yyPushParse(std::vector<YYTY Line 1628  static bool yyPushParse(std::vector<YYTY
1628      return true;      return true;
1629  }  }
1630    
1631    /**
1632     * Returns true if parsing ahead with given character @a ch is syntactially
1633     * valid according to the LSCP grammar, it returns false if it would create a
1634     * parse error.
1635     *
1636     * This is just a wrapper ontop of yyPushParse() which converts parser
1637     * exceptions thrown by yyPushParse() into negative return value.
1638     */
1639  static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch) {  static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch) {
1640      try {      try {
1641          return yyPushParse(stack, ch);          return yyPushParse(stack, ch);
# Line 1471  static bool yyValid(std::vector<YYTYPE_I Line 1649  static bool yyValid(std::vector<YYTYPE_I
1649      }      }
1650  }  }
1651    
1652  static int yyValidCharacters(std::vector<YYTYPE_INT16>& stack, const String& line) {  /**
1653     * Returns the amount of correct characters of given @a line from the left,
1654     * according to the LSCP grammar.
1655     *
1656     * @param stack - a Bison symbol state stack to work with
1657     * @param line  - the input line to check
1658     * @param bAutoCorrect - if true: try to correct obvious, trivial syntax errors
1659     */
1660    static int yyValidCharacters(std::vector<YYTYPE_INT16>& stack, String& line, bool bAutoCorrect) {
1661      int i;      int i;
1662      for (i = 0; i < line.size(); ++i) {      for (i = 0; i < line.size(); ++i) {
1663          if (!yyValid(stack, line[i])) return i;          // since we might check the same parser state twice against the current
1664            // char here below, and since the state stack might be altered
1665            // (i.e. shifted or reduced) on syntax errors, we have to backup the
1666            // current state stack and restore it on syntax errors below
1667            std::vector<YYTYPE_INT16> stackBackup = stack;
1668            if (yyValid(stackBackup, line[i])) {
1669                stack = stackBackup;
1670                continue;
1671            }
1672            if (bAutoCorrect) {
1673                // try trivial corrections, i.e. upper case character instead of
1674                // lower case, subline instead of space and vice versa
1675                char c;
1676                if      (line[i] == ' ') c = '_';
1677                else if (line[i] == '_') c = ' ';
1678                else if (isLowerCaseAlphaChar(line[i]))
1679                    c = alphaCharToUpperCase(line[i]);
1680                else return i;
1681                if (yyValid(stack, c)) {
1682                    line[i] = c;
1683                    continue;
1684                }
1685            }
1686            return i;
1687      }      }
1688      return i;      return i;
1689  }  }
# Line 1485  static int yyValidCharacters(std::vector Line 1694  static int yyValidCharacters(std::vector
1694   * error appeared.   * error appeared.
1695   */   */
1696  static std::set<String> yyExpectedSymbols() {  static std::set<String> yyExpectedSymbols() {
1697      std::set<String> result;      std::map<String,BisonSymbolInfo> expectedSymbols;
1698      yyparse_param_t* param = GetCurrentYaccSession();      yyparse_param_t* param = GetCurrentYaccSession();
1699      YYTYPE_INT16* ss = (*param->ppStackBottom);      YYTYPE_INT16* ss = (*param->ppStackBottom);
1700      YYTYPE_INT16* sp = (*param->ppStackTop);      YYTYPE_INT16* sp = (*param->ppStackTop);
# Line 1495  static std::set<String> yyExpectedSymbol Line 1704  static std::set<String> yyExpectedSymbol
1704      for (int i = 0; i < iStackSize; ++i) {      for (int i = 0; i < iStackSize; ++i) {
1705          stack.push_back(ss[i]);          stack.push_back(ss[i]);
1706      }      }
1707        String notUsedHere;
1708      // do the actual parser work      // do the actual parser work
1709      walkAndFillExpectedSymbols(stack, result);      walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere);
1710    
1711        // convert expectedSymbols to the result set
1712        std::set<String> result;
1713        for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1714             it != expectedSymbols.end(); ++it) result.insert(it->first);
1715      return result;      return result;
1716  }  }
1717    
1718  namespace LinuxSampler {  namespace LinuxSampler {
1719    
1720    #define DEBUG_SHELL_INTERACTION 0
1721    
1722    /**
1723     * If LSP shell mode is enabled, then this function is called on every new
1724     * received from client. It will check the current total input line and reply
1725     * to the LSCP shell for providing colored syntax highlighting and potential
1726     * auto completion in the shell.
1727     *
1728     * It also performs auto correction of obvious & trivial syntax mistakes if
1729     * requested.
1730     */
1731  String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param) {  String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param) {
1732        // first, determine how many characters (starting from the left) of the
1733        // given input line are already syntactially correct
1734      std::vector<YYTYPE_INT16> stack;      std::vector<YYTYPE_INT16> stack;
1735      stack.push_back(0); // every Bison symbol stack starts with zero      stack.push_back(0); // every Bison symbol stack starts with state zero
1736      String l = line + '\n';      String l = line + '\n'; // '\n' to pretend ENTER as if the line was now complete
1737      int n = yyValidCharacters(stack, l);      int n = yyValidCharacters(stack, l, param->bShellAutoCorrect);
1738    
1739        // if auto correction is enabled, apply the auto corrected string to
1740        // intput/output string 'line'
1741        if (param->bShellAutoCorrect) {
1742            int nMin = (n < line.length()) ? n : line.length();
1743            line.replace(0, nMin, l.substr(0, nMin));
1744        }
1745    
1746        // generate an info string that will be sent to the LSCP shell for letting
1747        // it know which part is correct, which one is wrong, where is the cursor, etc.
1748      String result = line;      String result = line;
1749      result.insert(n <= result.length() ? n : result.length(), LSCP_SHK_GOOD_FRONT);      result.insert(n <= result.length() ? n : result.length(), LSCP_SHK_GOOD_FRONT);
1750      int code = (n > line.length()) ? LSCP_SHU_COMPLETE : (n < line.length()) ?      int code = (n > line.length()) ? LSCP_SHU_COMPLETE : (n < line.length()) ?
1751                 LSCP_SHU_SYNTAX_ERR : LSCP_SHU_INCOMPLETE;                 LSCP_SHU_SYNTAX_ERR : LSCP_SHU_INCOMPLETE;
1752      result = "SHU:" + ToString(code) + ":" + result;      result = "SHU:" + ToString(code) + ":" + result + LSCP_SHK_CURSOR;
1753      //if (n > line.length()) result += " [OK]";      //if (n > line.length()) result += " [OK]";
1754  #if DEBUG_PUSH_PARSE  
1755        // get a clean parser stack to the last valid parse position
1756        // (due to the appended '\n' character above, and on syntax errors, the
1757        // state stack might be in undesired, i.e. reduced state)
1758        stack.clear();
1759        stack.push_back(0); // every Bison symbol stack starts with state zero
1760        l = line.substr(0, n);
1761        if (!l.empty()) yyValidCharacters(stack, l, param->bShellAutoCorrect);
1762    
1763        // generate auto completion suggestion (based on the current parser stack)
1764        std::map<String,BisonSymbolInfo> expectedSymbols;
1765        String notUsedHere;
1766        walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere);
1767        if (expectedSymbols.size() == 1) {
1768            String name          = expectedSymbols.begin()->first;
1769            BisonSymbolInfo info = expectedSymbols.begin()->second;
1770    #if DEBUG_SHELL_INTERACTION
1771            printf("Suggested Completion (%d): %s '%s'\n", expectedSymbols.size(), (info.isTerminalSymbol) ? "T:" : "NT:", (name + " (" + info.nextExpectedChars + ")").c_str());
1772    #endif
1773            result += LSCP_SHK_SUGGEST_BACK + info.nextExpectedChars;
1774        } else if (expectedSymbols.size() == 0) {
1775    #if DEBUG_SHELL_INTERACTION
1776            printf("No suggestion.\n");
1777    #endif
1778        } else if (expectedSymbols.size() > 1) {
1779    #if DEBUG_SHELL_INTERACTION
1780            printf("Multiple possibilities:");
1781            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1782                 it != expectedSymbols.end(); ++it)
1783            {
1784                printf(" %s (..%s)", it->first.c_str(), it->second.nextExpectedChars.c_str());
1785            }
1786            printf("\n");
1787    #endif
1788            // check if any of the possibilites is a non-terminal symbol, if so, we
1789            // have no way for auto completion at this point
1790            bool bNonTerminalExists = false;
1791            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1792                 it != expectedSymbols.end(); ++it) if (!it->second.isTerminalSymbol) { bNonTerminalExists = true; break; };
1793            if (!bNonTerminalExists) {
1794                // all possibilites are terminal symbaols, so try to find the least
1795                // common string all possibilites start with from the left
1796                String sCommon;
1797                for (int i = 0; true; ++i) {
1798                    char c;
1799                    for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1800                         it != expectedSymbols.end(); ++it)
1801                    {
1802                        if (i >= it->second.nextExpectedChars.size())
1803                            goto commonSearchEndLabel;
1804                        if (it == expectedSymbols.begin())
1805                            c = it->second.nextExpectedChars[i];
1806                        if (c != it->second.nextExpectedChars[i])
1807                            goto commonSearchEndLabel;
1808                        if (it == --expectedSymbols.end())
1809                            sCommon += c;
1810                    }
1811                }
1812                commonSearchEndLabel:
1813                if (!sCommon.empty()) result += LSCP_SHK_SUGGEST_BACK + sCommon;
1814    #if DEBUG_SHELL_INTERACTION
1815                printf("Common possibility: '%s'\n", sCommon.c_str());
1816    #endif
1817            }
1818        }
1819    
1820    #if DEBUG_SHELL_INTERACTION
1821      printf("%s\n", result.c_str());      printf("%s\n", result.c_str());
1822  #endif  #endif
1823    
1824      return result;      return result;
1825  }  }
1826    

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

  ViewVC Help
Powered by ViewVC