/[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 2518 by schoenebeck, Sat Feb 8 00:49:30 2014 UTC revision 2524 by schoenebeck, Sun Feb 23 19:26:59 2014 UTC
# Line 196  void yyerror(void* x, const char* s) { Line 196  void yyerror(void* x, const char* s) {
196  %type <Char> char char_base alpha_char digit digit_oct digit_hex escape_seq escape_seq_octal escape_seq_hex  %type <Char> char char_base alpha_char digit digit_oct digit_hex escape_seq escape_seq_octal escape_seq_hex
197  %type <Dotnum> real dotnum volume_value boolean control_value  %type <Dotnum> real dotnum volume_value boolean control_value
198  %type <Number> number sampler_channel instrument_index fx_send_id audio_channel_index device_index effect_index effect_instance effect_chain chain_pos input_control midi_input_channel_index midi_input_port_index midi_map midi_bank midi_prog midi_ctrl  %type <Number> number sampler_channel instrument_index fx_send_id audio_channel_index device_index effect_index effect_instance effect_chain chain_pos input_control midi_input_channel_index midi_input_port_index midi_map midi_bank midi_prog midi_ctrl
199  %type <String> string string_escaped text text_escaped text_escaped_base stringval stringval_escaped digits param_val_list param_val query_val filename module effect_system db_path map_name entry_name fx_send_name effect_name engine_name command add_instruction create_instruction destroy_instruction get_instruction list_instruction load_instruction send_instruction set_chan_instruction load_instr_args load_engine_args audio_output_type_name midi_input_type_name remove_instruction unmap_instruction set_instruction subscribe_event unsubscribe_event map_instruction reset_instruction clear_instruction find_instruction move_instruction copy_instruction scan_mode edit_instruction format_instruction append_instruction insert_instruction  %type <String> string string_escaped text text_escaped text_escaped_base stringval stringval_escaped digits param_val_list param_val query_val filename module effect_system db_path map_name entry_name fx_send_name effect_name engine_name line statement command add_instruction create_instruction destroy_instruction get_instruction list_instruction load_instruction send_instruction set_chan_instruction load_instr_args load_engine_args audio_output_type_name midi_input_type_name remove_instruction unmap_instruction set_instruction subscribe_event unsubscribe_event map_instruction reset_instruction clear_instruction find_instruction move_instruction copy_instruction scan_mode edit_instruction format_instruction append_instruction insert_instruction
200  %type <FillResponse> buffer_size_type  %type <FillResponse> buffer_size_type
201  %type <KeyValList> key_val_list query_val_list  %type <KeyValList> key_val_list query_val_list
202  %type <LoadMode> instr_load_mode  %type <LoadMode> instr_load_mode
# Line 218  void yyerror(void* x, const char* s) { Line 218  void yyerror(void* x, const char* s) {
218    
219  // GRAMMAR_BNF_BEGIN - do NOT delete or modify this line !!!  // GRAMMAR_BNF_BEGIN - do NOT delete or modify this line !!!
220    
221  input                 : line LF  input                 :  line   { INCREMENT_LINE; if (!$1.empty()) LSCPSERVER->AnswerClient($1); return LSCP_DONE; }
222                        | line CR LF                        |  error  { INCREMENT_LINE; LSCPSERVER->AnswerClient("ERR:0:" + sLastError + "\r\n"); RESTART; return LSCP_SYNTAX_ERROR; }
223                        ;                        ;
224    
225  line                  :  /* epsilon (empty line ignored) */ { INCREMENT_LINE; return LSCP_DONE; }  line                  :  statement LF     { $$ = $1; }
226                        |  comment  { INCREMENT_LINE; return LSCP_DONE; }                        |  statement CR LF  { $$ = $1; }
227                        |  command  { INCREMENT_LINE; LSCPSERVER->AnswerClient($1); return LSCP_DONE; }                        ;
228                        |  error    { INCREMENT_LINE; LSCPSERVER->AnswerClient("ERR:0:" + sLastError + "\r\n"); RESTART; return LSCP_SYNTAX_ERROR; }  
229    statement             :  /* epsilon (empty statement/line ignored) */  { $$ = ""; }
230                          |  comment  { $$ = ""; }
231                          |  command
232                        ;                        ;
233    
234  comment               :  '#'  comment               :  '#'
# Line 1345  inline static BisonSymbolInfo _symbolInf Line 1348  inline static BisonSymbolInfo _symbolInf
1348    
1349  #else // Bison 2.x or older ...  #else // Bison 2.x or older ...
1350    
1351    //TODO: The Bison 2.x code below can probably soon just be deleted. Most Bisonx 2.x versions should be able to compile successfully with the Bison 3.x code above as well (just requires the existence of table yystos[] in the auto generated lscpparser.cpp).
1352    
1353  /**  /**
1354   * Returns true if the given grammar @a rule is a terminal symbol (in *our*   * Returns true if the given grammar @a rule is a terminal symbol (in *our*
1355   * terms).   * terms).
# Line 1403  inline static String _tokenName(int toke Line 1408  inline static String _tokenName(int toke
1408      return s;      return s;
1409  }  }
1410    
1411    /**
1412     * Assumes the given @a token is exactly one character and returns that
1413     * character. This must be changed in future, i.e. in case Unicode characters
1414     * will be introduced in the LSCP grammar one day.
1415     */
1416    inline static char _tokenChar(int token) {
1417        String s = _tokenName(token);
1418        if (s == "\\n") return '\n';
1419        if (s == "\\r") return '\r';
1420        return _tokenName(token)[0];
1421    }
1422    
1423    /**
1424     * Implements Bison's so called "reduce" action, according to Bison's LALR(1)
1425     * parser algorithm.
1426     */
1427    inline static int _yyReduce(std::vector<YYTYPE_INT16>& stack, const int& rule) {
1428        if (stack.empty()) throw 1; // severe error
1429        const int len = yyr2[rule];
1430        stack.resize(stack.size() - len);
1431        YYTYPE_INT16 newState = yypgoto[yyr1[rule] - YYNTOKENS] + stack.back();
1432        if (0 <= newState && newState <= YYLAST && yycheck[newState] == stack.back())
1433            newState = yytable[newState];
1434        else
1435            newState = yydefgoto[yyr1[rule] - YYNTOKENS];
1436        stack.push_back(newState);
1437        return newState;
1438    }
1439    
1440    /**
1441     * Implements Bison's so called "default reduce" action, according to Bison's
1442     * LALR(1) parser algorithm.
1443     */
1444    inline static int _yyDefaultReduce(std::vector<YYTYPE_INT16>& stack) {
1445        if (stack.empty()) throw 2; // severe error
1446        int rule = yydefact[stack.back()];
1447        if (rule <= 0 || rule >= YYNRULES) throw 3; // no rule, something is wrong
1448        return _yyReduce(stack, rule);
1449    }
1450    
1451    static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch);
1452    
1453  #define DEBUG_BISON_SYNTAX_ERROR_WALKER 0  #define DEBUG_BISON_SYNTAX_ERROR_WALKER 0
1454    
1455  /**  /**
# Line 1441  static void walkAndFillExpectedSymbols( Line 1488  static void walkAndFillExpectedSymbols(
1488      }      }
1489      printf("\n");      printf("\n");
1490  #endif  #endif
1491        startLabel:
1492    
1493      if (stack.empty()) return;      if (stack.empty()) {
1494    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1495            for (int i = 0; i < depth; ++i) printf("\t");
1496            printf("(EMPTY STACK)\n");
1497    #endif
1498            return;
1499        }
1500    
1501      int state = stack[stack.size() - 1];      int state = stack[stack.size() - 1];
1502      int n = yypact[state];      int n = yypact[state];
1503      if (n == YYPACT_NINF) { // default reduction required ...      if (n == YYPACT_NINF) { // default reduction required ...
1504          // get default reduction rule for this state          // get default reduction rule for this state
1505          n = yydefact[state];          n = yydefact[state];
1506          if (n <= 0 || n >= YYNRULES) return; // no rule, something is wrong          if (n <= 0 || n >= YYNRULES) {
1507          // return the new resolved expected symbol (left-hand symbol of grammar  #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1508          // rule), then we're done in this state              for (int i = 0; i < depth; ++i) printf("\t");
1509                printf("(EMPTY RULE)\n");
1510    #endif
1511                return; // no rule, something is wrong
1512            }
1513    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1514            for (int i = 0; i < depth; ++i) printf("\t");
1515            printf("(default reduction)\n");
1516    #endif
1517          #if HAVE_BISON_MAJ >= 3          #if HAVE_BISON_MAJ >= 3
1518          expectedSymbols[yytname[yyr1[n]]] = _symbolInfoForRule(n, stack, nextExpectedChars);          if (!nextExpectedChars.empty() || !_isRuleTerminalSymbol(n, stack)) {
1519          #else          #else
1520          expectedSymbols[yytname[yyr1[n]]] = _symbolInfoForRule(n, nextExpectedChars);          if (!nextExpectedChars.empty() || !_isRuleTerminalSymbol(n)) {
1521          #endif          #endif
1522                // Return the new resolved expected symbol (left-hand symbol of grammar
1523                // rule), then we're done in this state. (If the same symbol can be
1524                // matched on different ways, then it is non-terminal symbol.)
1525                bool ambigious =
1526                    expectedSymbols.count(yytname[yyr1[n]]) &&
1527                    expectedSymbols[yytname[yyr1[n]]].nextExpectedChars != nextExpectedChars;
1528                #if HAVE_BISON_MAJ >= 3
1529                expectedSymbols[yytname[yyr1[n]]] = _symbolInfoForRule(n, stack, nextExpectedChars);
1530                #else
1531                expectedSymbols[yytname[yyr1[n]]] = _symbolInfoForRule(n, nextExpectedChars);
1532                #endif
1533                if (ambigious)
1534                    expectedSymbols[yytname[yyr1[n]]].isTerminalSymbol = false;
1535    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1536                for (int i = 0; i < depth; ++i) printf("\t");
1537                printf("(empty expectedChars. sym = %s)\n", yytname[yyr1[n]]);
1538    #endif
1539                return;
1540            }
1541            _yyReduce(stack, n);
1542            goto startLabel;
1543        }
1544        if (!(YYPACT_NINF < n && n <= YYLAST)) {
1545    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1546            for (int i = 0; i < depth; ++i) printf("\t");
1547            printf("(invalid action B)\n");
1548    #endif
1549          return;          return;
1550      }      }
1551      if (!(YYPACT_NINF < n && n <= YYLAST)) return;  
1552        // Check for duplicate states, if duplicates exist return
1553        // (this check is necessary since the introduction of the yyValid() call
1554        // below, which does not care about duplicates).
1555        for (int i = 0; i < stack.size(); ++i)
1556            for (int k = i + 1; k < stack.size(); ++k)
1557                if (stack[i] == stack[k])
1558                    return;
1559    
1560  #if DEBUG_BISON_SYNTAX_ERROR_WALKER  #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1561      for (int i = 0; i < depth; ++i) printf("\t");      for (int i = 0; i < depth; ++i) printf("\t");
1562      printf("Expected tokens:");      printf("Expected tokens:");
1563  #endif  #endif
1564      int begin = n < 0 ? -n : 0;      int begin = n < 0 ? -n : 0;
1565      int checklim = YYLAST - n + 1;      //int checklim = YYLAST - n + 1;
1566      int end = checklim < YYNTOKENS ? checklim : YYNTOKENS;      int end = YYNTOKENS;//checklim < YYNTOKENS ? checklim : YYNTOKENS;
1567      int rule, action, stackSize, nextExpectedCharsLen;      int rule, action, stackSize, nextExpectedCharsLen;
1568      for (int token = begin; token < end; ++token) {      for (int token = begin; token < end; ++token) {
1569          if (token == YYTERROR || yycheck[n + token] != token) continue;          if (token <= YYTERROR) continue;
1570            if (yytname[token] == String("$undefined")) continue;
1571            if (yytname[token] == String("EXT_ASCII_CHAR")) continue;
1572            //if (yycheck[n + token] != token) goto default_reduction;
1573            if (yycheck[n + token] != token) { // default reduction suggested ...
1574                // If we are here, it means the current token in the loop would not
1575                // cause a "shift", however we don't already know whether this token
1576                // is valid or not. Because there might be several reductions
1577                // involved until one can determine whether the token causes an
1578                // error or is valid. So we use this heavy check instead:
1579                std::vector<YYTYPE_INT16> stackCopy = stack; // copy required, since reduction will take place
1580                if (!yyValid(stackCopy, _tokenChar(token))) continue; // invalid token
1581  #if DEBUG_BISON_SYNTAX_ERROR_WALKER  #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1582          printf(" %s", yytname[token]);              printf(" ETdr(%s)", yytname[token]);
1583    #endif
1584                // the token is valid, "stackCopy" has been reduced accordingly
1585                // and now do recurse ...
1586                nextExpectedChars += _tokenName(token);
1587                nextExpectedCharsLen = nextExpectedChars.size();
1588                walkAndFillExpectedSymbols( //FIXME: could cause stack overflow (should be a loop instead), is probably fine with our current grammar though
1589                    stackCopy, expectedSymbols, nextExpectedChars, depth + 1
1590                );
1591                nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'
1592                continue;
1593            }
1594    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1595            printf(" ET(%s)", yytname[token]);
1596  #endif  #endif
   
         //if (yycheck[n + token] != token) goto default_reduction;  
1597    
1598          action = yytable[n + token];          action = yytable[n + token];
1599          if (action == 0 || action == YYTABLE_NINF) {          if (action == 0 || action == YYTABLE_NINF) {
1600  #if DEBUG_BISON_SYNTAX_ERROR_WALKER  #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1601              printf(" (invalid action) "); fflush(stdout);              printf(" (invalid action A) "); fflush(stdout);
1602  #endif  #endif
1603              continue; // error, ignore              continue; // error, ignore
1604          }          }
# Line 1491  static void walkAndFillExpectedSymbols( Line 1609  static void walkAndFillExpectedSymbols(
1609              rule = -action;              rule = -action;
1610              goto reduce;              goto reduce;
1611          }          }
1612          if (action == YYFINAL) continue; // "accept" state, we don't care about it here          if (action == YYFINAL) {
1613    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1614                printf(" (ACCEPT) "); fflush(stdout);
1615    #endif
1616                continue; // "accept" state, we don't care about it here
1617            }
1618    
1619          // "shift" required ...          // "shift" required ...
1620    
1621          if (std::find(stack.begin(), stack.end(), action) != stack.end())          if (std::find(stack.begin(), stack.end(), action) != stack.end()) {
1622    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1623                printf(" (duplicate state %d) ", action); fflush(stdout);
1624    #endif
1625              continue; // duplicate state, ignore it to avoid endless recursions              continue; // duplicate state, ignore it to avoid endless recursions
1626            }
1627    
1628          // "shift" / push the new state on the state stack and call this          // "shift" / push the new state on the state stack and call this
1629          // function recursively, and restore the stack after the recurse return          // function recursively, and restore the stack after the recurse return
# Line 1519  static void walkAndFillExpectedSymbols( Line 1646  static void walkAndFillExpectedSymbols(
1646  #if DEBUG_BISON_SYNTAX_ERROR_WALKER  #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1647          printf(" (reduce by %d) ", rule); fflush(stdout);          printf(" (reduce by %d) ", rule); fflush(stdout);
1648  #endif  #endif
1649          if (rule == 0 || rule >= YYNRULES) continue; // invalid rule, something is wrong          if (rule == 0 || rule >= YYNRULES) {
1650          // store the left-hand symbol of the grammar rule  #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1651                printf(" (invalid rule) "); fflush(stdout);
1652    #endif
1653                continue; // invalid rule, something is wrong
1654            }
1655            // Store the left-hand symbol of the grammar rule. (If the same symbol
1656            // can be matched on different ways, then it is non-terminal symbol.)
1657            bool ambigious =
1658                expectedSymbols.count(yytname[yyr1[rule]]) &&
1659                expectedSymbols[yytname[yyr1[rule]]].nextExpectedChars != nextExpectedChars;
1660          #if HAVE_BISON_MAJ >= 3          #if HAVE_BISON_MAJ >= 3
1661          expectedSymbols[yytname[yyr1[rule]]] = _symbolInfoForRule(rule, stack, nextExpectedChars);          expectedSymbols[yytname[yyr1[rule]]] = _symbolInfoForRule(rule, stack, nextExpectedChars);
1662          #else          #else
1663          expectedSymbols[yytname[yyr1[rule]]] = _symbolInfoForRule(rule, nextExpectedChars);          expectedSymbols[yytname[yyr1[rule]]] = _symbolInfoForRule(rule, nextExpectedChars);
1664          #endif          #endif
1665            if (ambigious)
1666                expectedSymbols[yytname[yyr1[n]]].isTerminalSymbol = false;
1667  #if DEBUG_BISON_SYNTAX_ERROR_WALKER  #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1668          printf(" (SYM %s) ", yytname[yyr1[rule]]); fflush(stdout);          printf(" (SYM %s) ", yytname[yyr1[rule]]); fflush(stdout);
1669  #endif  #endif
# Line 1535  static void walkAndFillExpectedSymbols( Line 1673  static void walkAndFillExpectedSymbols(
1673  #endif  #endif
1674  }  }
1675    
 /**  
  * Implements Bison's so called "reduce" action, according to Bison's LALR(1)  
  * parser algorithm.  
  */  
 inline static int _yyReduce(std::vector<YYTYPE_INT16>& stack, const int& rule) {  
     if (stack.empty()) throw 1; // severe error  
     const int len = yyr2[rule];  
     stack.resize(stack.size() - len);  
     YYTYPE_INT16 newState = yypgoto[yyr1[rule] - YYNTOKENS] + stack.back();  
     if (0 <= newState && newState <= YYLAST && yycheck[newState] == stack.back())  
         newState = yytable[newState];  
     else  
         newState = yydefgoto[yyr1[rule] - YYNTOKENS];  
     stack.push_back(newState);  
     return newState;  
 }  
   
 /**  
  * Implements Bison's so called "default reduce" action, according to Bison's  
  * LALR(1) parser algorithm.  
  */  
 inline static int _yyDefaultReduce(std::vector<YYTYPE_INT16>& stack) {  
     if (stack.empty()) throw 2; // severe error  
     int rule = yydefact[stack.back()];  
     if (rule <= 0 || rule >= YYNRULES) throw 3; // no rule, something is wrong  
     return _yyReduce(stack, rule);  
 }  
   
1676  #define DEBUG_PUSH_PARSE 0  #define DEBUG_PUSH_PARSE 0
1677    
1678  /**  /**
# Line 1629  static bool yyPushParse(std::vector<YYTY Line 1739  static bool yyPushParse(std::vector<YYTY
1739  }  }
1740    
1741  /**  /**
1742   * Returns true if parsing ahead with given character @a ch is syntactially   * Returns true if parsing ahead with given character @a ch is syntactically
1743   * valid according to the LSCP grammar, it returns false if it would create a   * valid according to the LSCP grammar, it returns false if it would create a
1744   * parse error.   * parse error.
1745   *   *
1746     * The @a stack will reflect the new parser state after this call.
1747     *
1748   * This is just a wrapper ontop of yyPushParse() which converts parser   * This is just a wrapper ontop of yyPushParse() which converts parser
1749   * exceptions thrown by yyPushParse() into negative return value.   * exceptions thrown by yyPushParse() into negative return value.
1750   */   */
# Line 1664  static int yyValidCharacters(std::vector Line 1776  static int yyValidCharacters(std::vector
1776          // char here below, and since the state stack might be altered          // char here below, and since the state stack might be altered
1777          // (i.e. shifted or reduced) on syntax errors, we have to backup the          // (i.e. shifted or reduced) on syntax errors, we have to backup the
1778          // current state stack and restore it on syntax errors below          // current state stack and restore it on syntax errors below
1779          std::vector<YYTYPE_INT16> stackBackup = stack;          std::vector<YYTYPE_INT16> stackCopy = stack;
1780          if (yyValid(stackBackup, line[i])) {          if (yyValid(stackCopy, line[i])) {
1781              stack = stackBackup;              stack = stackCopy;
1782              continue;              continue;
1783          }          }
1784          if (bAutoCorrect) {          if (bAutoCorrect) {
# Line 1692  static int yyValidCharacters(std::vector Line 1804  static int yyValidCharacters(std::vector
1804   * Should only be called on syntax errors: returns a set of non-terminal   * Should only be called on syntax errors: returns a set of non-terminal
1805   * symbols expected to appear now/next, just at the point where the syntax   * symbols expected to appear now/next, just at the point where the syntax
1806   * error appeared.   * error appeared.
1807     *
1808     * @returns names of the non-terminal symbols expected at this parse position
1809   */   */
1810  static std::set<String> yyExpectedSymbols() {  static std::set<String> yyExpectedSymbols() {
1811      std::map<String,BisonSymbolInfo> expectedSymbols;      std::map<String,BisonSymbolInfo> expectedSymbols;
# Line 1715  static std::set<String> yyExpectedSymbol Line 1829  static std::set<String> yyExpectedSymbol
1829      return result;      return result;
1830  }  }
1831    
1832    #define DEBUG_YY_AUTO_COMPLETE 0
1833    
1834    /**
1835     * A set of parser state stacks. This type is used in yyAutoComplete() to keep
1836     * track of all previous parser states, for detecting a parser state stack that
1837     * has already been before. Because if yyAutoComplete() reaches the exactly same
1838     * parser state stack again, it means there is an endless recursion in that
1839     * part of the grammar tree branch and shall not be evaluated any further,
1840     * because it would end up in an endless loop otherwise.
1841     *
1842     * This solution consumes a lot of memory, but unfortunately there is no other
1843     * easy way to solve it. With our grammar and today's memory heap & memory stack
1844     * it should be fine though.
1845     */
1846    typedef std::set< std::vector<YYTYPE_INT16> > YYStackHistory;
1847    
1848    /**
1849     * Generates and returns an auto completion string for the current parser
1850     * state given by @a stack.
1851     *
1852     * Regarding @a history argument: read the description on YYStackHistory for the
1853     * purpose behind this argument.
1854     *
1855     * @param stack - current Bison (yacc) state stack to create auto completion for
1856     * @param history - only for internal purpose, keeps a history of all previous parser state stacks
1857     * @param depth - just for internal debugging purposes
1858     * @returns auto completion for current, given parser state
1859     */
1860    static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack, YYStackHistory& history, int depth = 0) {
1861        std::map<String,BisonSymbolInfo> expectedSymbols;
1862        String notUsedHere;
1863        walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere);
1864        if (expectedSymbols.size() == 1) {
1865            String name          = expectedSymbols.begin()->first;
1866            BisonSymbolInfo info = expectedSymbols.begin()->second;
1867    #if DEBUG_YY_AUTO_COMPLETE
1868            for (int q = 0; q < depth; ++q) printf("  ");
1869            printf("(%d) Suggested Sub Completion (sz=%d): type=%s %s -> '%s'\n", depth, expectedSymbols.size(), (info.isTerminalSymbol) ? "T" : "NT", name.c_str(), info.nextExpectedChars.c_str());
1870    #endif
1871            if (info.nextExpectedChars.empty() || !info.isTerminalSymbol) return "";
1872            // parse forward with the suggested auto completion
1873            std::vector<YYTYPE_INT16> stackCopy = stack;
1874            yyValidCharacters(stackCopy, info.nextExpectedChars, false);
1875            // detect endless recursion
1876            if (history.count(stackCopy)) return "";
1877            history.insert(stackCopy);
1878            // recurse and return the expanded auto completion with maximum length
1879            return info.nextExpectedChars + yyAutoComplete(stackCopy, history, depth + 1);
1880        } else if (expectedSymbols.size() == 0) {
1881    #if DEBUG_YY_AUTO_COMPLETE
1882            for (int q = 0; q < depth; ++q) printf("  ");
1883            printf("(%d) No sub suggestion.\n", depth);
1884    #endif
1885            return "";
1886        } else if (expectedSymbols.size() > 1) {
1887    #if DEBUG_YY_AUTO_COMPLETE
1888            for (int q = 0; q < depth; ++q) printf("  ");
1889            printf("(%d) Multiple sub possibilities (before expansion):", depth);
1890            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1891                 it != expectedSymbols.end(); ++it)
1892            {
1893                printf(" %s (..%s)", it->first.c_str(), it->second.nextExpectedChars.c_str());
1894            }
1895            printf("\n");
1896    #endif
1897            // check if any of the possibilites is a non-terminal symbol, if so, we
1898            // have no way for auto completion at this point
1899            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1900                 it != expectedSymbols.end(); ++it)
1901            {
1902                if (!it->second.isTerminalSymbol) {
1903    #if DEBUG_YY_AUTO_COMPLETE
1904                    for (int q = 0; q < depth; ++q) printf("  ");
1905                    printf("(%d) Non-terminal exists. Stop.", depth);
1906    #endif
1907                    return "";
1908                }
1909            }
1910    #if 0 // commented out for now, since practically irrelevant and VERY slow ...
1911            // all possibilities are terminal symbols, so expand all possiblities to
1912            // maximum length with a recursive call for each possibility
1913            for (std::map<String,BisonSymbolInfo>::iterator it = expectedSymbols.begin();
1914                 it != expectedSymbols.end(); ++it)
1915            {
1916                if (it->second.nextExpectedChars.empty() || !it->second.isTerminalSymbol) continue;
1917                // parse forward with this particular suggested auto completion
1918                std::vector<YYTYPE_INT16> stackCopy = stack;
1919                yyValidCharacters(stackCopy, it->second.nextExpectedChars, false);
1920                // detect endless recursion
1921                if (history.count(stackCopy)) continue;
1922                history.insert(stackCopy);
1923                // recurse and return the total possible auto completion for this
1924                // grammar tree branch
1925                it->second.nextExpectedChars += yyAutoComplete(stackCopy, history, depth + 1);
1926            }
1927    #endif
1928            // try to find the longest common string all possibilities start with
1929            // (from the left)
1930            String sCommon;
1931            for (int i = 0; true; ++i) {
1932                char c;
1933                for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1934                     it != expectedSymbols.end(); ++it)
1935                {
1936                    if (i >= it->second.nextExpectedChars.size())
1937                        goto commonSearchEndLabel;
1938                    if (it == expectedSymbols.begin())
1939                        c = it->second.nextExpectedChars[i];
1940                    if (c != it->second.nextExpectedChars[i])
1941                        goto commonSearchEndLabel;
1942                    if (it == --expectedSymbols.end())
1943                        sCommon += c;
1944                }
1945            }
1946            commonSearchEndLabel:
1947    #if DEBUG_YY_AUTO_COMPLETE
1948            for (int q = 0; q < depth; ++q) printf("  ");
1949            printf("(%d) Multiple sub possibilities (after expansion):", depth);
1950            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1951                 it != expectedSymbols.end(); ++it)
1952            {
1953                printf(" %s (..%s)", it->first.c_str(), it->second.nextExpectedChars.c_str());
1954            }
1955            printf("\n");
1956            for (int q = 0; q < depth; ++q) printf("  ");
1957            printf("(%d) Common sub possibility: '%s'\n", depth, sCommon.c_str());
1958    #endif
1959            return sCommon;
1960        }
1961        return ""; // just pro forma, should never happen though
1962    }
1963    
1964    /**
1965     * Just a convenience wrapper on top of the actual yyAutoComplete()
1966     * implementation. See description above for details.
1967     */
1968    static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack) {
1969        YYStackHistory history;
1970        return yyAutoComplete(stack, history);
1971    }
1972    
1973  namespace LinuxSampler {  namespace LinuxSampler {
1974    
1975  #define DEBUG_SHELL_INTERACTION 0  #define DEBUG_SHELL_INTERACTION 0
1976    
1977  /**  /**
1978   * If LSP shell mode is enabled, then this function is called on every new   * If LSCP shell mode is enabled for the respective LSCP client connection, then
1979   * received from client. It will check the current total input line and reply   * this function is called on every new byte received from that client. It will
1980   * to the LSCP shell for providing colored syntax highlighting and potential   * check the current total input line and reply to the LSCP shell for providing
1981   * auto completion in the shell.   * colored syntax highlighting and potential auto completion in the shell.
1982   *   *
1983   * It also performs auto correction of obvious & trivial syntax mistakes if   * It also performs auto correction of obvious & trivial syntax mistakes if
1984   * requested.   * requested.
1985     *
1986     * The return value of this function will be sent to the client. It contains one
1987     * line specially formatted for the LSCP shell, which can easily be processed by
1988     * the client/shell for gettings its necessary informations like which part of
1989     * the current command line is syntactically correct, which part is incorrect,
1990     * what could be auto completed right now, etc.
1991     *
1992     * @returns LSCP shell response line to be returned to the client
1993   */   */
1994  String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param) {  String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param) {
1995      // first, determine how many characters (starting from the left) of the      // first, determine how many characters (starting from the left) of the
1996      // given input line are already syntactially correct      // given input line are already syntactically correct
1997      std::vector<YYTYPE_INT16> stack;      std::vector<YYTYPE_INT16> stack;
1998      stack.push_back(0); // every Bison symbol stack starts with state zero      stack.push_back(0); // every Bison symbol stack starts with state zero
1999      String l = line + '\n'; // '\n' to pretend ENTER as if the line was now complete      String l = line + '\n'; // '\n' to pretend ENTER as if the line was now complete
# Line 1761  String lscpParserProcessShellInteraction Line 2024  String lscpParserProcessShellInteraction
2024      if (!l.empty()) yyValidCharacters(stack, l, param->bShellAutoCorrect);      if (!l.empty()) yyValidCharacters(stack, l, param->bShellAutoCorrect);
2025    
2026      // generate auto completion suggestion (based on the current parser stack)      // generate auto completion suggestion (based on the current parser stack)
2027      std::map<String,BisonSymbolInfo> expectedSymbols;      String sSuggestion = yyAutoComplete(stack);
2028      String notUsedHere;      if (!sSuggestion.empty()) result += LSCP_SHK_SUGGEST_BACK + sSuggestion;
     walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere);  
     if (expectedSymbols.size() == 1) {  
         String name          = expectedSymbols.begin()->first;  
         BisonSymbolInfo info = expectedSymbols.begin()->second;  
 #if DEBUG_SHELL_INTERACTION  
         printf("Suggested Completion (%d): %s '%s'\n", expectedSymbols.size(), (info.isTerminalSymbol) ? "T:" : "NT:", (name + " (" + info.nextExpectedChars + ")").c_str());  
 #endif  
         result += LSCP_SHK_SUGGEST_BACK + info.nextExpectedChars;  
     } else if (expectedSymbols.size() == 0) {  
 #if DEBUG_SHELL_INTERACTION  
         printf("No suggestion.\n");  
 #endif  
     } else if (expectedSymbols.size() > 1) {  
 #if DEBUG_SHELL_INTERACTION  
         printf("Multiple possibilities:");  
         for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();  
              it != expectedSymbols.end(); ++it)  
         {  
             printf(" %s (..%s)", it->first.c_str(), it->second.nextExpectedChars.c_str());  
         }  
         printf("\n");  
 #endif  
         // check if any of the possibilites is a non-terminal symbol, if so, we  
         // have no way for auto completion at this point  
         bool bNonTerminalExists = false;  
         for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();  
              it != expectedSymbols.end(); ++it) if (!it->second.isTerminalSymbol) { bNonTerminalExists = true; break; };  
         if (!bNonTerminalExists) {  
             // all possibilites are terminal symbaols, so try to find the least  
             // common string all possibilites start with from the left  
             String sCommon;  
             for (int i = 0; true; ++i) {  
                 char c;  
                 for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();  
                      it != expectedSymbols.end(); ++it)  
                 {  
                     if (i >= it->second.nextExpectedChars.size())  
                         goto commonSearchEndLabel;  
                     if (it == expectedSymbols.begin())  
                         c = it->second.nextExpectedChars[i];  
                     if (c != it->second.nextExpectedChars[i])  
                         goto commonSearchEndLabel;  
                     if (it == --expectedSymbols.end())  
                         sCommon += c;  
                 }  
             }  
             commonSearchEndLabel:  
             if (!sCommon.empty()) result += LSCP_SHK_SUGGEST_BACK + sCommon;  
 #if DEBUG_SHELL_INTERACTION  
             printf("Common possibility: '%s'\n", sCommon.c_str());  
 #endif  
         }  
     }  
2029    
2030  #if DEBUG_SHELL_INTERACTION  #if DEBUG_SHELL_INTERACTION
2031      printf("%s\n", result.c_str());      printf("%s\n", result.c_str());

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

  ViewVC Help
Powered by ViewVC