/[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 3052 by schoenebeck, Wed Dec 14 17:34:54 2016 UTC
# Line 34  Line 34 
34  #include "lscpparser.h"  #include "lscpparser.h"
35  #include "lscpserver.h"  #include "lscpserver.h"
36  #include "lscpevent.h"  #include "lscpevent.h"
37  #include "lscpsymbols.h"  
38    #if AC_APPLE_UNIVERSAL_BUILD
39    # include "lscp.tab.h"
40    #else
41    # include "lscpsymbols.h"
42    #endif
43    
44  #include <algorithm>  #include <algorithm>
45  #include "lscp.h"  #include "lscp.h"
46    
# Line 43  namespace LinuxSampler { Line 49  namespace LinuxSampler {
49  // to save us typing work in the rules action definitions  // to save us typing work in the rules action definitions
50  #define LSCPSERVER ((yyparse_param_t*) yyparse_param)->pServer  #define LSCPSERVER ((yyparse_param_t*) yyparse_param)->pServer
51  #define SESSION_PARAM ((yyparse_param_t*) yyparse_param)  #define SESSION_PARAM ((yyparse_param_t*) yyparse_param)
52  #define INCREMENT_LINE { SESSION_PARAM->iLine++; SESSION_PARAM->iColumn = 0; sParsed.clear(); }  #define INCREMENT_LINE { SESSION_PARAM->onNextLine(); sParsed.clear(); }
53    
54  // clears input buffer  // clears input buffer
55  void restart(yyparse_param_t* pparam, int& yychar);  void restart(yyparse_param_t* pparam, int& yychar);
# Line 444  set_instruction       :  AUDIO_OUTPUT_DE Line 450  set_instruction       :  AUDIO_OUTPUT_DE
450                        |  ECHO SP boolean                                                                  { $$ = LSCPSERVER->SetEcho((yyparse_param_t*) yyparse_param, $3);  }                        |  ECHO SP boolean                                                                  { $$ = LSCPSERVER->SetEcho((yyparse_param_t*) yyparse_param, $3);  }
451                        |  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); }
452                        |  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); }
453                          |  SHELL SP DOC SP boolean                                                          { $$ = LSCPSERVER->SetShellDoc((yyparse_param_t*) yyparse_param, $5); }
454                        |  VOLUME SP volume_value                                                           { $$ = LSCPSERVER->SetGlobalVolume($3);                            }                        |  VOLUME SP volume_value                                                           { $$ = LSCPSERVER->SetGlobalVolume($3);                            }
455                        |  VOICES SP number                                                                 { $$ = LSCPSERVER->SetGlobalMaxVoices($3);                         }                        |  VOICES SP number                                                                 { $$ = LSCPSERVER->SetGlobalMaxVoices($3);                         }
456                        |  STREAMS SP number                                                                { $$ = LSCPSERVER->SetGlobalMaxStreams($3);                        }                        |  STREAMS SP number                                                                { $$ = LSCPSERVER->SetGlobalMaxStreams($3);                        }
# Line 1281  NAME                  :  'N''A''M''E' Line 1288  NAME                  :  'N''A''M''E'
1288  ECHO                  :  'E''C''H''O'  ECHO                  :  'E''C''H''O'
1289                        ;                        ;
1290    
1291    DOC                   :  'D''O''C'
1292                          ;
1293    
1294  QUIT                  :  'Q''U''I''T'  QUIT                  :  'Q''U''I''T'
1295                        ;                        ;
1296    
# Line 1450  inline static int _yyDefaultReduce(std:: Line 1460  inline static int _yyDefaultReduce(std::
1460    
1461  static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch);  static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch);
1462    
1463    /**
1464     * A set of parser symbol stacks. This type is used for the recursive algorithms
1465     * in a) yyAutoComplete() and b) walkAndFillExpectedSymbols() for detecting
1466     * endless recursions.
1467     *
1468     * This unique container is used to keep track of all previous parser states
1469     * (stacks), for detecting a parser symbol stack that has already been
1470     * encountered before. Because if yyAutoComplete() or
1471     * walkAndFillExpectedSymbols() reach the exactly same parser symbol stack
1472     * again, that means there is an endless recursion in that part of the grammar
1473     * tree branch and shall not be evaluated any further, since it would end up in
1474     * an endless loop of the algorithm otherwise.
1475     *
1476     * This solution consumes a lot of memory, but unfortunately there is no other
1477     * easy way to solve it. With our grammar and today's usual memory heap size &
1478     * memory stack size in modern devices, it should be fine though.
1479     */
1480    typedef std::set< std::vector<YYTYPE_INT16> > YYStackHistory;
1481    
1482  #define DEBUG_BISON_SYNTAX_ERROR_WALKER 0  #define DEBUG_BISON_SYNTAX_ERROR_WALKER 0
1483    
1484  /**  /**
# Line 1471  static bool yyValid(std::vector<YYTYPE_I Line 1500  static bool yyValid(std::vector<YYTYPE_I
1500   * @param expectedSymbols - will be filled with next expected grammar symbols   * @param expectedSymbols - will be filled with next expected grammar symbols
1501   * @param nextExpectedChars - just for internal purpose, due to the recursive   * @param nextExpectedChars - just for internal purpose, due to the recursive
1502   *                            implementation of this function, do supply an   *                            implementation of this function, do supply an
1503   *                            empty character for this argument   *                            empty string for this argument
1504   * @param depth - just for internal debugging purposes   * @param history - only for internal purpose, keeps a history of all previous
1505     *                  parser symbol stacks (just for avoiding endless recursion in
1506     *                  this recursive algorithm), do supply an empty history
1507     * @param depth - just for internal debugging purposes, do not supply it
1508   */   */
1509  static void walkAndFillExpectedSymbols(  static void walkAndFillExpectedSymbols(
1510      std::vector<YYTYPE_INT16>& stack,      std::vector<YYTYPE_INT16>& stack,
1511      std::map<String,BisonSymbolInfo>& expectedSymbols,      std::map<String,BisonSymbolInfo>& expectedSymbols,
1512      String& nextExpectedChars, int depth = 0)      String& nextExpectedChars, YYStackHistory& history, int depth = 0)
1513  {  {
1514  #if DEBUG_BISON_SYNTAX_ERROR_WALKER  #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1515      printf("\n");      printf("\n");
# Line 1490  static void walkAndFillExpectedSymbols( Line 1522  static void walkAndFillExpectedSymbols(
1522  #endif  #endif
1523      startLabel:      startLabel:
1524    
1525        // detect endless recursion
1526        if (history.count(stack)) return;
1527        history.insert(stack);
1528    
1529      if (stack.empty()) {      if (stack.empty()) {
1530  #if DEBUG_BISON_SYNTAX_ERROR_WALKER  #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1531          for (int i = 0; i < depth; ++i) printf("\t");          for (int i = 0; i < depth; ++i) printf("\t");
# Line 1586  static void walkAndFillExpectedSymbols( Line 1622  static void walkAndFillExpectedSymbols(
1622              nextExpectedChars += _tokenName(token);              nextExpectedChars += _tokenName(token);
1623              nextExpectedCharsLen = nextExpectedChars.size();              nextExpectedCharsLen = nextExpectedChars.size();
1624              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
1625                  stackCopy, expectedSymbols, nextExpectedChars, depth + 1                  stackCopy, expectedSymbols, nextExpectedChars, history, depth + 1
1626              );              );
1627              nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'              nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'
1628              continue;              continue;
# Line 1632  static void walkAndFillExpectedSymbols( Line 1668  static void walkAndFillExpectedSymbols(
1668          stack.push_back(action);          stack.push_back(action);
1669          nextExpectedChars += _tokenName(token);          nextExpectedChars += _tokenName(token);
1670          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
1671              stack, expectedSymbols, nextExpectedChars, depth + 1              stack, expectedSymbols, nextExpectedChars, history, depth + 1
1672          );          );
1673          stack.resize(stackSize); // restore stack          stack.resize(stackSize); // restore stack
1674          nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'          nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'
# Line 1673  static void walkAndFillExpectedSymbols( Line 1709  static void walkAndFillExpectedSymbols(
1709  #endif  #endif
1710  }  }
1711    
1712    /**
1713     * Just a convenience wrapper on top of the actual walkAndFillExpectedSymbols()
1714     * implementation above, which can be called with less parameters than the
1715     * implementing function above actually requires.
1716     */
1717    static void walkAndFillExpectedSymbols(
1718        std::vector<YYTYPE_INT16>& stack,
1719        std::map<String,BisonSymbolInfo>& expectedSymbols)
1720    {
1721        String nextExpectedChars;
1722        YYStackHistory history;
1723    
1724        walkAndFillExpectedSymbols(
1725            stack, expectedSymbols, nextExpectedChars, history
1726        );
1727    }
1728    
1729  #define DEBUG_PUSH_PARSE 0  #define DEBUG_PUSH_PARSE 0
1730    
1731  /**  /**
1732   * Implements parsing exactly one character (given by @a c), continueing at the   * Implements parsing exactly one character (given by @a ch), continueing at the
1733   * 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
1734   * state after this call.   * state after this call.
1735   *   *
# Line 1746  static bool yyPushParse(std::vector<YYTY Line 1799  static bool yyPushParse(std::vector<YYTY
1799   * The @a stack will reflect the new parser state after this call.   * The @a stack will reflect the new parser state after this call.
1800   *   *
1801   * This is just a wrapper ontop of yyPushParse() which converts parser   * This is just a wrapper ontop of yyPushParse() which converts parser
1802   * exceptions thrown by yyPushParse() into negative return value.   * exceptions thrown by yyPushParse() into @c false return value.
1803   */   */
1804  static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch) {  static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch) {
1805      try {      try {
# Line 1818  static std::set<String> yyExpectedSymbol Line 1871  static std::set<String> yyExpectedSymbol
1871      for (int i = 0; i < iStackSize; ++i) {      for (int i = 0; i < iStackSize; ++i) {
1872          stack.push_back(ss[i]);          stack.push_back(ss[i]);
1873      }      }
     String notUsedHere;  
1874      // do the actual parser work      // do the actual parser work
1875      walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere);      walkAndFillExpectedSymbols(stack, expectedSymbols);
1876    
1877      // convert expectedSymbols to the result set      // convert expectedSymbols to the result set
1878      std::set<String> result;      std::set<String> result;
# Line 1832  static std::set<String> yyExpectedSymbol Line 1884  static std::set<String> yyExpectedSymbol
1884  #define DEBUG_YY_AUTO_COMPLETE 0  #define DEBUG_YY_AUTO_COMPLETE 0
1885    
1886  /**  /**
  * 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;  
   
 /**  
1887   * Generates and returns an auto completion string for the current parser   * Generates and returns an auto completion string for the current parser
1888   * 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
1889   * 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 1906  typedef std::set< std::vector<YYTYPE_INT
1906   * @param stack - current Bison (yacc) symbol stack to create auto completion for   * @param stack - current Bison (yacc) symbol stack to create auto completion for
1907   * @param history - only for internal purpose, keeps a history of all previous   * @param history - only for internal purpose, keeps a history of all previous
1908   *                  parser symbol stacks (just for avoiding endless recursion in   *                  parser symbol stacks (just for avoiding endless recursion in
1909   *                  this auto completion algorithm)   *                  this auto completion algorithm), do supply an empty history
1910   * @param depth - just for internal debugging purposes   * @param depth - just for internal debugging purposes, do not supply anything
1911   * @returns auto completion for current, given parser state   * @returns auto completion for current, given parser state
1912   */   */
1913  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) {
1914      std::map<String,BisonSymbolInfo> expectedSymbols;      std::map<String,BisonSymbolInfo> expectedSymbols;
1915      String notUsedHere;      walkAndFillExpectedSymbols(stack, expectedSymbols);
     walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere);  
1916      if (expectedSymbols.size() == 1) {      if (expectedSymbols.size() == 1) {
1917          String name          = expectedSymbols.begin()->first;          String name          = expectedSymbols.begin()->first;
1918          BisonSymbolInfo info = expectedSymbols.begin()->second;          BisonSymbolInfo info = expectedSymbols.begin()->second;
# Line 1978  static String yyAutoComplete(std::vector Line 2015  static String yyAutoComplete(std::vector
2015    
2016  /**  /**
2017   * Just a convenience wrapper on top of the actual yyAutoComplete()   * Just a convenience wrapper on top of the actual yyAutoComplete()
2018   * implementation. See description above for details.   * implementation. See its description above for details.
2019   */   */
2020  static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack) {  static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack) {
2021      YYStackHistory history;      YYStackHistory history;
# Line 2009  namespace LinuxSampler { Line 2046  namespace LinuxSampler {
2046   * 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
2047   * evaluation to the user on the screen.   * evaluation to the user on the screen.
2048   *   *
2049     * @param line - the current command line to be evaluated by LSCP parser
2050     * @param param = reentrant parser session parameters
2051     * @param possibilities - whether all possibilities shall be shown
2052   * @returns LSCP shell response line to be returned to the client   * @returns LSCP shell response line to be returned to the client
2053   */   */
2054  String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param) {  String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param, bool possibilities) {
2055      // first, determine how many characters (starting from the left) of the      // first, determine how many characters (starting from the left) of the
2056      // given input line are already syntactically correct      // given input line are already syntactically correct
2057      std::vector<YYTYPE_INT16> stack;      std::vector<YYTYPE_INT16> stack;
# Line 2026  String lscpParserProcessShellInteraction Line 2066  String lscpParserProcessShellInteraction
2066          line.replace(0, nMin, l.substr(0, nMin));          line.replace(0, nMin, l.substr(0, nMin));
2067      }      }
2068    
2069        size_t cursorPos = line.size() + param->iCursorOffset;
2070        if (cursorPos < 0) cursorPos = 0;
2071    
2072      // 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
2073      // 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.
2074      String result = line;      String result = line;
2075      result.insert(n <= result.length() ? n : result.length(), LSCP_SHK_GOOD_FRONT);      result.insert(n <= result.length() ? n : result.length(), LSCP_SHK_GOOD_FRONT);
2076        result.insert(cursorPos <= n ? cursorPos : cursorPos + String(LSCP_SHK_GOOD_FRONT).length(), LSCP_SHK_CURSOR);
2077      int code = (n > line.length()) ? LSCP_SHU_COMPLETE : (n < line.length()) ?      int code = (n > line.length()) ? LSCP_SHU_COMPLETE : (n < line.length()) ?
2078                 LSCP_SHU_SYNTAX_ERR : LSCP_SHU_INCOMPLETE;                 LSCP_SHU_SYNTAX_ERR : LSCP_SHU_INCOMPLETE;
2079      result = "SHU:" + ToString(code) + ":" + result + LSCP_SHK_CURSOR;      result = "SHU:" + ToString(code) + ":" + result;
2080      //if (n > line.length()) result += " [OK]";      //if (n > line.length()) result += " [OK]";
2081    
2082      // 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 2088  String lscpParserProcessShellInteraction
2088      if (!l.empty()) yyValidCharacters(stack, l, param->bShellAutoCorrect);      if (!l.empty()) yyValidCharacters(stack, l, param->bShellAutoCorrect);
2089    
2090      // generate auto completion suggestion (based on the current parser stack)      // generate auto completion suggestion (based on the current parser stack)
2091      String sSuggestion = yyAutoComplete(stack);      std::vector<YYTYPE_INT16> stackCopy = stack; // make a copy, since yyAutoComplete() might alter the stack
2092        String sSuggestion = yyAutoComplete(stackCopy);
2093      if (!sSuggestion.empty()) result += LSCP_SHK_SUGGEST_BACK + sSuggestion;      if (!sSuggestion.empty()) result += LSCP_SHK_SUGGEST_BACK + sSuggestion;
2094    
2095        if (possibilities) {
2096            // append all possible terminals and non-terminals according to
2097            // current parser state
2098            std::map<String,BisonSymbolInfo> expectedSymbols;
2099            walkAndFillExpectedSymbols(stack, expectedSymbols);
2100    
2101            // pretend to LSCP shell that the following terminal symbols were
2102            // non-terminal symbols (since they are not human visible for auto
2103            // completion on the shell's screen)
2104            std::set<String> specialNonTerminals;
2105            specialNonTerminals.insert("SP");
2106            specialNonTerminals.insert("CR");
2107            specialNonTerminals.insert("LF");
2108    
2109            String sPossibilities;
2110            int iNonTerminals = 0;
2111            int iTerminals    = 0;
2112            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
2113                 it != expectedSymbols.end(); ++it)
2114            {
2115                if (!sPossibilities.empty()) sPossibilities += " | ";
2116                if (it->second.isTerminalSymbol && !specialNonTerminals.count(it->first)) {
2117                    sPossibilities += it->first;
2118                    iTerminals++;
2119                } else {
2120                    sPossibilities += "<" + it->first + ">";
2121                    iNonTerminals++;
2122                }
2123            }
2124            if (!sPossibilities.empty() && (iNonTerminals || iTerminals > 1)) {
2125                result += LSCP_SHK_POSSIBILITIES_BACK + sPossibilities;
2126            }
2127        }
2128    
2129  #if DEBUG_SHELL_INTERACTION  #if DEBUG_SHELL_INTERACTION
2130      printf("%s\n", result.c_str());      printf("%s\n", result.c_str());
2131  #endif  #endif

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

  ViewVC Help
Powered by ViewVC