/[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 2525 by schoenebeck, Mon Feb 24 17:52:51 2014 UTC revision 2534 by schoenebeck, Sun Mar 9 21:34:03 2014 UTC
# Line 43  namespace LinuxSampler { Line 43  namespace LinuxSampler {
43  // to save us typing work in the rules action definitions  // to save us typing work in the rules action definitions
44  #define LSCPSERVER ((yyparse_param_t*) yyparse_param)->pServer  #define LSCPSERVER ((yyparse_param_t*) yyparse_param)->pServer
45  #define SESSION_PARAM ((yyparse_param_t*) yyparse_param)  #define SESSION_PARAM ((yyparse_param_t*) yyparse_param)
46  #define INCREMENT_LINE { SESSION_PARAM->iLine++; SESSION_PARAM->iColumn = 0; sParsed.clear(); }  #define INCREMENT_LINE { SESSION_PARAM->onNextLine(); sParsed.clear(); }
47    
48  // clears input buffer  // clears input buffer
49  void restart(yyparse_param_t* pparam, int& yychar);  void restart(yyparse_param_t* pparam, int& yychar);
# Line 444  set_instruction       :  AUDIO_OUTPUT_DE Line 444  set_instruction       :  AUDIO_OUTPUT_DE
444                        |  ECHO SP boolean                                                                  { $$ = LSCPSERVER->SetEcho((yyparse_param_t*) yyparse_param, $3);  }                        |  ECHO SP boolean                                                                  { $$ = LSCPSERVER->SetEcho((yyparse_param_t*) yyparse_param, $3);  }
445                        |  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); }
446                        |  SHELL SP AUTO_CORRECT SP boolean                                                 { $$ = LSCPSERVER->SetShellAutoCorrect((yyparse_param_t*) yyparse_param, $5); }                        |  SHELL SP AUTO_CORRECT SP boolean                                                 { $$ = LSCPSERVER->SetShellAutoCorrect((yyparse_param_t*) yyparse_param, $5); }
447                          |  SHELL SP DOC SP boolean                                                          { $$ = LSCPSERVER->SetShellDoc((yyparse_param_t*) yyparse_param, $5); }
448                        |  VOLUME SP volume_value                                                           { $$ = LSCPSERVER->SetGlobalVolume($3);                            }                        |  VOLUME SP volume_value                                                           { $$ = LSCPSERVER->SetGlobalVolume($3);                            }
449                        |  VOICES SP number                                                                 { $$ = LSCPSERVER->SetGlobalMaxVoices($3);                         }                        |  VOICES SP number                                                                 { $$ = LSCPSERVER->SetGlobalMaxVoices($3);                         }
450                        |  STREAMS SP number                                                                { $$ = LSCPSERVER->SetGlobalMaxStreams($3);                        }                        |  STREAMS SP number                                                                { $$ = LSCPSERVER->SetGlobalMaxStreams($3);                        }
# Line 1281  NAME                  :  'N''A''M''E' Line 1282  NAME                  :  'N''A''M''E'
1282  ECHO                  :  'E''C''H''O'  ECHO                  :  'E''C''H''O'
1283                        ;                        ;
1284    
1285    DOC                   :  'D''O''C'
1286                          ;
1287    
1288  QUIT                  :  'Q''U''I''T'  QUIT                  :  'Q''U''I''T'
1289                        ;                        ;
1290    
# Line 1450  inline static int _yyDefaultReduce(std:: Line 1454  inline static int _yyDefaultReduce(std::
1454    
1455  static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch);  static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch);
1456    
1457    /**
1458     * A set of parser symbol stacks. This type is used for the recursive algorithms
1459     * in a) yyAutoComplete() and b) walkAndFillExpectedSymbols() for detecting
1460     * endless recursions.
1461     *
1462     * This unique container is used to keep track of all previous parser states
1463     * (stacks), for detecting a parser symbol stack that has already been
1464     * encountered before. Because if yyAutoComplete() or
1465     * walkAndFillExpectedSymbols() reach the exactly same parser symbol stack
1466     * again, that means there is an endless recursion in that part of the grammar
1467     * tree branch and shall not be evaluated any further, since it would end up in
1468     * an endless loop of the algorithm otherwise.
1469     *
1470     * This solution consumes a lot of memory, but unfortunately there is no other
1471     * easy way to solve it. With our grammar and today's usual memory heap size &
1472     * memory stack size in modern devices, it should be fine though.
1473     */
1474    typedef std::set< std::vector<YYTYPE_INT16> > YYStackHistory;
1475    
1476  #define DEBUG_BISON_SYNTAX_ERROR_WALKER 0  #define DEBUG_BISON_SYNTAX_ERROR_WALKER 0
1477    
1478  /**  /**
# Line 1471  static bool yyValid(std::vector<YYTYPE_I Line 1494  static bool yyValid(std::vector<YYTYPE_I
1494   * @param expectedSymbols - will be filled with next expected grammar symbols   * @param expectedSymbols - will be filled with next expected grammar symbols
1495   * @param nextExpectedChars - just for internal purpose, due to the recursive   * @param nextExpectedChars - just for internal purpose, due to the recursive
1496   *                            implementation of this function, do supply an   *                            implementation of this function, do supply an
1497   *                            empty character for this argument   *                            empty string for this argument
1498   * @param depth - just for internal debugging purposes   * @param history - only for internal purpose, keeps a history of all previous
1499     *                  parser symbol stacks (just for avoiding endless recursion in
1500     *                  this recursive algorithm), do supply an empty history
1501     * @param depth - just for internal debugging purposes, do not supply it
1502   */   */
1503  static void walkAndFillExpectedSymbols(  static void walkAndFillExpectedSymbols(
1504      std::vector<YYTYPE_INT16>& stack,      std::vector<YYTYPE_INT16>& stack,
1505      std::map<String,BisonSymbolInfo>& expectedSymbols,      std::map<String,BisonSymbolInfo>& expectedSymbols,
1506      String& nextExpectedChars, int depth = 0)      String& nextExpectedChars, YYStackHistory& history, int depth = 0)
1507  {  {
1508  #if DEBUG_BISON_SYNTAX_ERROR_WALKER  #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1509      printf("\n");      printf("\n");
# Line 1490  static void walkAndFillExpectedSymbols( Line 1516  static void walkAndFillExpectedSymbols(
1516  #endif  #endif
1517      startLabel:      startLabel:
1518    
1519        // detect endless recursion
1520        if (history.count(stack)) return;
1521        history.insert(stack);
1522    
1523      if (stack.empty()) {      if (stack.empty()) {
1524  #if DEBUG_BISON_SYNTAX_ERROR_WALKER  #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1525          for (int i = 0; i < depth; ++i) printf("\t");          for (int i = 0; i < depth; ++i) printf("\t");
# Line 1586  static void walkAndFillExpectedSymbols( Line 1616  static void walkAndFillExpectedSymbols(
1616              nextExpectedChars += _tokenName(token);              nextExpectedChars += _tokenName(token);
1617              nextExpectedCharsLen = nextExpectedChars.size();              nextExpectedCharsLen = nextExpectedChars.size();
1618              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
1619                  stackCopy, expectedSymbols, nextExpectedChars, depth + 1                  stackCopy, expectedSymbols, nextExpectedChars, history, depth + 1
1620              );              );
1621              nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'              nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'
1622              continue;              continue;
# Line 1632  static void walkAndFillExpectedSymbols( Line 1662  static void walkAndFillExpectedSymbols(
1662          stack.push_back(action);          stack.push_back(action);
1663          nextExpectedChars += _tokenName(token);          nextExpectedChars += _tokenName(token);
1664          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
1665              stack, expectedSymbols, nextExpectedChars, depth + 1              stack, expectedSymbols, nextExpectedChars, history, depth + 1
1666          );          );
1667          stack.resize(stackSize); // restore stack          stack.resize(stackSize); // restore stack
1668          nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'          nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'
# Line 1673  static void walkAndFillExpectedSymbols( Line 1703  static void walkAndFillExpectedSymbols(
1703  #endif  #endif
1704  }  }
1705    
1706    /**
1707     * Just a convenience wrapper on top of the actual walkAndFillExpectedSymbols()
1708     * implementation above, which can be called with less parameters than the
1709     * implementing function above actually requires.
1710     */
1711    static void walkAndFillExpectedSymbols(
1712        std::vector<YYTYPE_INT16>& stack,
1713        std::map<String,BisonSymbolInfo>& expectedSymbols)
1714    {
1715        String nextExpectedChars;
1716        YYStackHistory history;
1717    
1718        walkAndFillExpectedSymbols(
1719            stack, expectedSymbols, nextExpectedChars, history
1720        );
1721    }
1722    
1723  #define DEBUG_PUSH_PARSE 0  #define DEBUG_PUSH_PARSE 0
1724    
1725  /**  /**
1726   * Implements parsing exactly one character (given by @a c), continueing at the   * Implements parsing exactly one character (given by @a ch), continueing at the
1727   * parser position reflected by @a stack. The @a stack will hold the new parser   * parser position reflected by @a stack. The @a stack will hold the new parser
1728   * state after this call.   * state after this call.
1729   *   *
# Line 1746  static bool yyPushParse(std::vector<YYTY Line 1793  static bool yyPushParse(std::vector<YYTY
1793   * The @a stack will reflect the new parser state after this call.   * The @a stack will reflect the new parser state after this call.
1794   *   *
1795   * This is just a wrapper ontop of yyPushParse() which converts parser   * This is just a wrapper ontop of yyPushParse() which converts parser
1796   * exceptions thrown by yyPushParse() into negative return value.   * exceptions thrown by yyPushParse() into @c false return value.
1797   */   */
1798  static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch) {  static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch) {
1799      try {      try {
# Line 1818  static std::set<String> yyExpectedSymbol Line 1865  static std::set<String> yyExpectedSymbol
1865      for (int i = 0; i < iStackSize; ++i) {      for (int i = 0; i < iStackSize; ++i) {
1866          stack.push_back(ss[i]);          stack.push_back(ss[i]);
1867      }      }
     String notUsedHere;  
1868      // do the actual parser work      // do the actual parser work
1869      walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere);      walkAndFillExpectedSymbols(stack, expectedSymbols);
1870    
1871      // convert expectedSymbols to the result set      // convert expectedSymbols to the result set
1872      std::set<String> result;      std::set<String> result;
# Line 1832  static std::set<String> yyExpectedSymbol Line 1878  static std::set<String> yyExpectedSymbol
1878  #define DEBUG_YY_AUTO_COMPLETE 0  #define DEBUG_YY_AUTO_COMPLETE 0
1879    
1880  /**  /**
  * A set of parser symbol stacks. This type is used in yyAutoComplete() to keep  
  * track of all previous parser states, for detecting a parser symbol stack that  
  * has already been before. Because if yyAutoComplete() reaches the exactly same  
  * parser symbol stack again, it means there is an endless recursion in that  
  * part of the grammar tree branch and shall not be evaluated any further,  
  * because it would end up in an endless loop otherwise.  
  *  
  * This solution consumes a lot of memory, but unfortunately there is no other  
  * easy way to solve it. With our grammar and today's memory heap & memory stack  
  * it should be fine though.  
  */  
 typedef std::set< std::vector<YYTYPE_INT16> > YYStackHistory;  
   
 /**  
1881   * Generates and returns an auto completion string for the current parser   * Generates and returns an auto completion string for the current parser
1882   * state given by @a stack. That means, this function will return the longest   * state given by @a stack. That means, this function will return the longest
1883   * sequence of characters that is uniqueley expected to be sent next by the LSCP   * sequence of characters that is uniqueley expected to be sent next by the LSCP
# Line 1868  typedef std::set< std::vector<YYTYPE_INT Line 1900  typedef std::set< std::vector<YYTYPE_INT
1900   * @param stack - current Bison (yacc) symbol stack to create auto completion for   * @param stack - current Bison (yacc) symbol stack to create auto completion for
1901   * @param history - only for internal purpose, keeps a history of all previous   * @param history - only for internal purpose, keeps a history of all previous
1902   *                  parser symbol stacks (just for avoiding endless recursion in   *                  parser symbol stacks (just for avoiding endless recursion in
1903   *                  this auto completion algorithm)   *                  this auto completion algorithm), do supply an empty history
1904   * @param depth - just for internal debugging purposes   * @param depth - just for internal debugging purposes, do not supply anything
1905   * @returns auto completion for current, given parser state   * @returns auto completion for current, given parser state
1906   */   */
1907  static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack, YYStackHistory& history, int depth = 0) {  static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack, YYStackHistory& history, int depth = 0) {
1908      std::map<String,BisonSymbolInfo> expectedSymbols;      std::map<String,BisonSymbolInfo> expectedSymbols;
1909      String notUsedHere;      walkAndFillExpectedSymbols(stack, expectedSymbols);
     walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere);  
1910      if (expectedSymbols.size() == 1) {      if (expectedSymbols.size() == 1) {
1911          String name          = expectedSymbols.begin()->first;          String name          = expectedSymbols.begin()->first;
1912          BisonSymbolInfo info = expectedSymbols.begin()->second;          BisonSymbolInfo info = expectedSymbols.begin()->second;
# Line 1978  static String yyAutoComplete(std::vector Line 2009  static String yyAutoComplete(std::vector
2009    
2010  /**  /**
2011   * Just a convenience wrapper on top of the actual yyAutoComplete()   * Just a convenience wrapper on top of the actual yyAutoComplete()
2012   * implementation. See description above for details.   * implementation. See its description above for details.
2013   */   */
2014  static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack) {  static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack) {
2015      YYStackHistory history;      YYStackHistory history;
# Line 2009  namespace LinuxSampler { Line 2040  namespace LinuxSampler {
2040   * application will only have to show the results of the LSCP server's   * application will only have to show the results of the LSCP server's
2041   * evaluation to the user on the screen.   * evaluation to the user on the screen.
2042   *   *
2043     * @param line - the current command line to be evaluated by LSCP parser
2044     * @param param = reentrant parser session parameters
2045     * @param possibilities - whether all possibilities shall be shown
2046   * @returns LSCP shell response line to be returned to the client   * @returns LSCP shell response line to be returned to the client
2047   */   */
2048  String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param) {  String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param, bool possibilities) {
2049      // first, determine how many characters (starting from the left) of the      // first, determine how many characters (starting from the left) of the
2050      // given input line are already syntactically correct      // given input line are already syntactically correct
2051      std::vector<YYTYPE_INT16> stack;      std::vector<YYTYPE_INT16> stack;
# Line 2026  String lscpParserProcessShellInteraction Line 2060  String lscpParserProcessShellInteraction
2060          line.replace(0, nMin, l.substr(0, nMin));          line.replace(0, nMin, l.substr(0, nMin));
2061      }      }
2062    
2063        size_t cursorPos = line.size() + param->iCursorOffset;
2064        if (cursorPos < 0) cursorPos = 0;
2065    
2066      // generate an info string that will be sent to the LSCP shell for letting      // generate an info string that will be sent to the LSCP shell for letting
2067      // it know which part is correct, which one is wrong, where is the cursor, etc.      // it know which part is correct, which one is wrong, where is the cursor, etc.
2068      String result = line;      String result = line;
2069      result.insert(n <= result.length() ? n : result.length(), LSCP_SHK_GOOD_FRONT);      result.insert(n <= result.length() ? n : result.length(), LSCP_SHK_GOOD_FRONT);
2070        result.insert(cursorPos <= n ? cursorPos : cursorPos + String(LSCP_SHK_GOOD_FRONT).length(), LSCP_SHK_CURSOR);
2071      int code = (n > line.length()) ? LSCP_SHU_COMPLETE : (n < line.length()) ?      int code = (n > line.length()) ? LSCP_SHU_COMPLETE : (n < line.length()) ?
2072                 LSCP_SHU_SYNTAX_ERR : LSCP_SHU_INCOMPLETE;                 LSCP_SHU_SYNTAX_ERR : LSCP_SHU_INCOMPLETE;
2073      result = "SHU:" + ToString(code) + ":" + result + LSCP_SHK_CURSOR;      result = "SHU:" + ToString(code) + ":" + result;
2074      //if (n > line.length()) result += " [OK]";      //if (n > line.length()) result += " [OK]";
2075    
2076      // get a clean parser stack to the last valid parse position      // get a clean parser stack to the last valid parse position
# Line 2044  String lscpParserProcessShellInteraction Line 2082  String lscpParserProcessShellInteraction
2082      if (!l.empty()) yyValidCharacters(stack, l, param->bShellAutoCorrect);      if (!l.empty()) yyValidCharacters(stack, l, param->bShellAutoCorrect);
2083    
2084      // generate auto completion suggestion (based on the current parser stack)      // generate auto completion suggestion (based on the current parser stack)
2085      String sSuggestion = yyAutoComplete(stack);      std::vector<YYTYPE_INT16> stackCopy = stack; // make a copy, since yyAutoComplete() might alter the stack
2086        String sSuggestion = yyAutoComplete(stackCopy);
2087      if (!sSuggestion.empty()) result += LSCP_SHK_SUGGEST_BACK + sSuggestion;      if (!sSuggestion.empty()) result += LSCP_SHK_SUGGEST_BACK + sSuggestion;
2088    
2089        if (possibilities) {
2090            // append all possible terminals and non-terminals according to
2091            // current parser state
2092            std::map<String,BisonSymbolInfo> expectedSymbols;
2093            walkAndFillExpectedSymbols(stack, expectedSymbols);
2094    
2095            // pretend to LSCP shell that the following terminal symbols were
2096            // non-terminal symbols (since they are not human visible for auto
2097            // completion on the shell's screen)
2098            std::set<String> specialNonTerminals;
2099            specialNonTerminals.insert("SP");
2100            specialNonTerminals.insert("CR");
2101            specialNonTerminals.insert("LF");
2102    
2103            String sPossibilities;
2104            int iNonTerminals = 0;
2105            int iTerminals    = 0;
2106            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
2107                 it != expectedSymbols.end(); ++it)
2108            {
2109                if (!sPossibilities.empty()) sPossibilities += " | ";
2110                if (it->second.isTerminalSymbol && !specialNonTerminals.count(it->first)) {
2111                    sPossibilities += it->first;
2112                    iTerminals++;
2113                } else {
2114                    sPossibilities += "<" + it->first + ">";
2115                    iNonTerminals++;
2116                }
2117            }
2118            if (!sPossibilities.empty() && (iNonTerminals || iTerminals > 1)) {
2119                result += LSCP_SHK_POSSIBILITIES_BACK + sPossibilities;
2120            }
2121        }
2122    
2123  #if DEBUG_SHELL_INTERACTION  #if DEBUG_SHELL_INTERACTION
2124      printf("%s\n", result.c_str());      printf("%s\n", result.c_str());
2125  #endif  #endif

Legend:
Removed from v.2525  
changed lines
  Added in v.2534

  ViewVC Help
Powered by ViewVC