/[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 185 by senkov, Wed Jul 7 02:49:51 2004 UTC revision 4002 by schoenebeck, Mon Nov 22 20:06:26 2021 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6     *   Copyright (C) 2005 - 2020 Christian Schoenebeck                       *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
9   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 20  Line 21 
21   *   MA  02111-1307  USA                                                   *   *   MA  02111-1307  USA                                                   *
22   ***************************************************************************/   ***************************************************************************/
23    
24    /*
25        The parser's C++ source files should be automatically (re)generated if
26        this file was modified. If not, or in case you want explicitly
27        regenerate the parser C++ files, run 'make parser'. In both cases you
28        need to have bison or another yacc compatible parser generator
29        installed though.
30    */
31    
32  %{  %{
33    
34  #include "lscpparser.h"  #include "lscpparser.h"
35  #include "lscpserver.h"  #include "lscpserver.h"
36  #include "lscpevent.h"  #include "lscpevent.h"
37    
38  // as we need an reentrant scanner, we have to pass the pointer to the scanner with each yylex() call  #if AC_APPLE_UNIVERSAL_BUILD
39  #define YYLEX_PARAM ((yyparse_param_t*) yyparse_param)->pScanner  # include "lscp.tab.h"
40    #else
41    # include "lscpsymbols.h"
42    #endif
43    
44    #include <algorithm>
45    #include "lscp.h"
46    
47    namespace LinuxSampler {
48    
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)
52    #define INCREMENT_LINE { SESSION_PARAM->onNextLine(); sParsed.clear(); }
53    
54  // clears input buffer and restarts scanner.  // clears input buffer
55  void restart(yyparse_param_t* pparam, int& yychar);  void restart(yyparse_param_t* pparam, int& yychar);
56  #define RESTART restart((yyparse_param_t*) YYPARSE_PARAM, yychar)  #define RESTART restart((yyparse_param_t*) YYPARSE_PARAM, yychar)
57    
58  // external reference to the main scanner function yylex()  static char buf[1024]; // input buffer to feed the parser with new characters
59  extern YY_DECL;  static int bytes = 0;  // current number of characters in the input buffer
60    static int ptr   = 0;  // current position in the input buffer
61    static String sLastError; // error message of the last error occured
62    static String sParsed; ///< Characters of current line which have already been shifted (consumed/parsed) by the parser.
63    
64    // external reference to the function which actually reads from the socket
65    extern int GetLSCPCommand( void *buf, int max_size);
66    
67    // external reference to the function in lscpserver.cpp which returns the
68    // current session (only works because the server runs as singleton)
69    extern yyparse_param_t* GetCurrentYaccSession();
70    
71    // returns true if supplied characters has an ASCII code of 128 or higher
72    inline bool isExtendedAsciiChar(const char c) {
73        return (c < 0);
74    }
75    
76    // returns true if the given character is between between a to z.
77    inline bool isLowerCaseAlphaChar(const char c) {
78        return c >= 'a' && c <= 'z';
79    }
80    
81    // converts the given (expected) lower case character to upper case
82    inline char alphaCharToUpperCase(const char c) {
83        return (c - 'a') + 'A';
84    }
85    
86    // custom scanner function which reads from the socket
87    // (bison expects it to return the numerical ID of the next
88    // "recognized token" from the input stream)
89    int yylex(YYSTYPE* yylval) {
90        // check if we have to read new characters
91        if (ptr >= bytes) {
92            bytes = GetLSCPCommand(buf, 1023);
93            ptr   = 0;
94            if (bytes < 0) {
95                bytes = 0;
96                return 0;
97            }
98        }
99        // this is the next character in the input stream
100        const char c = buf[ptr++];
101        // increment current reading position (just for verbosity / messages)
102        GetCurrentYaccSession()->iColumn++;
103        sParsed += c;
104        // we have to handle "normal" and "extended" ASCII characters separately
105        if (isExtendedAsciiChar(c)) {
106            // workaround for characters with ASCII code higher than 127
107            yylval->Char = c;
108            return EXT_ASCII_CHAR;
109        } else {
110            // simply return the ASCII code as terminal symbol ID
111            return (int) c;
112        }
113    }
114    
115    // parser helper functions
116    
117    int octalsToNumber(char oct_digit0, char oct_digit1 = '0', char oct_digit2 = '0') {
118        const char d0[] = { oct_digit0, '\0' };
119        const char d1[] = { oct_digit1, '\0' };
120        const char d2[] = { oct_digit2, '\0' };
121        return atoi(d2)*8*8 + atoi(d1)*8 + atoi(d0);
122    }
123    
124    }
125    
126    using namespace LinuxSampler;
127    
128    static std::set<String> yyExpectedSymbols();
129    
130  // external reference to restart the lex scanner  /**
131  extern void yyrestart(FILE* input_file, yyscan_t yyscanner);   * Will be called when an error occured (usually syntax error).
132     *
133     * We provide our own version of yyerror() so we a) don't have to link against
134     * the yacc library and b) can render more helpful syntax error messages.
135     */
136    void yyerror(void* x, const char* s) {
137        yyparse_param_t* param = GetCurrentYaccSession();
138    
139  // we provide our own version of yyerror() so we don't have to link against the yacc library      // get the text part already parsed (of current line)
140  void yyerror(const char* s);      const bool bContainsLineFeed =
141            sParsed.find('\r') != std::string::npos ||
142            sParsed.find('\n') != std::string::npos;
143        // remove potential line feed characters
144        if (bContainsLineFeed) {
145            for (size_t p = sParsed.find('\r'); p != std::string::npos;
146                 p = sParsed.find('\r')) sParsed.erase(p);
147            for (size_t p = sParsed.find('\n'); p != std::string::npos;
148                 p = sParsed.find('\n')) sParsed.erase(p);
149        }
150    
151        // start assembling the error message with Bison's own message
152        String txt = s;
153    
154        // append exact position info of syntax error
155        txt += (" (line:"  + ToString(param->iLine+1)) +
156               (",column:" + ToString(param->iColumn)) + ")";
157    
158        // append the part of the lined that has already been parsed
159        txt += ". Context: \"" + sParsed;
160        if (txt.empty() || bContainsLineFeed)
161            txt += "^";
162        else
163            txt.insert(txt.size() - 1, "^");
164        txt += "...\"";
165    
166        // append the non-terminal symbols expected now/next
167        std::set<String> expectedSymbols = yyExpectedSymbols();
168        for (std::set<String>::const_iterator it = expectedSymbols.begin();
169             it != expectedSymbols.end(); ++it)
170        {
171            if (it == expectedSymbols.begin())
172                txt += " -> Should be: " + *it;
173            else
174                txt += " | " + *it;
175        }
176    
177        dmsg(2,("LSCPParser: %s\n", txt.c_str()));
178        sLastError = txt;
179    }
180    
181  %}  %}
182    
183  // reentrant parser  // reentrant parser
184  %pure_parser  %pure-parser
185    
186    %parse-param {void* yyparse_param}
187    
188    // After entering the yyparse() function, store references to the parser's
189    // symbol stack, so that we can create more helpful syntax error messages than
190    // Bison (2.x) could do.
191    %initial-action {
192        yyparse_param_t* p = (yyparse_param_t*) yyparse_param;
193        p->ppStackBottom = &yyss;
194        p->ppStackTop    = &yyssp;
195    }
196    
197    // tell bison to spit out verbose syntax error messages
198    %error-verbose
199    
200  %token <Char>   CHAR  %token <Char> EXT_ASCII_CHAR
201  %token <Dotnum> DOTNUM  
202  %token <Number> NUMBER  %type <Char> char char_base alpha_char digit digit_oct digit_hex escape_seq escape_seq_octal escape_seq_hex
203  %token <String> STRINGVAL  %type <Dotnum> real dotnum volume_value boolean control_value
204  %token SP LF CR HASH EQ  %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
205  %token ADD GET CREATE DESTROY LIST LOAD NON_MODAL REMOVE SET SUBSCRIBE UNSUBSCRIBE RESET QUIT  %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
 %token CHANNEL NOTIFICATION  
 %token AVAILABLE_ENGINES AVAILABLE_AUDIO_OUTPUT_DRIVERS CHANNELS INFO BUFFER_FILL STREAM_COUNT VOICE_COUNT  
 %token INSTRUMENT ENGINE  
 %token AUDIO_OUTPUT_CHANNEL AUDIO_OUTPUT_CHANNEL_PARAMETER AUDIO_OUTPUT_DEVICE AUDIO_OUTPUT_DEVICES AUDIO_OUTPUT_DEVICE_PARAMETER AUDIO_OUTPUT_DRIVER AUDIO_OUTPUT_DRIVER_PARAMETER AUDIO_OUTPUT_TYPE MIDI_INPUT MIDI_INPUT_TYPE MIDI_INPUT_PORT MIDI_INPUT_CHANNEL VOLUME  
 %token MIDI_INPUT_DRIVER MIDI_INPUT_DRIVER_PARAMETER AVAILABLE_MIDI_INPUT_DRIVERS MIDI_INPUT_DEVICE MIDI_INPUT_DEVICES MIDI_INPUT_DEVICE_PARAMETER MIDI_INPUT_PORT_PARAMETER  
 %token BYTES PERCENTAGE  
 %token MISCELLANEOUS  
   
 %type <Dotnum> volume  
 %type <Number> sampler_channel instrument_index audio_output_channel audio_output_device midi_input_channel midi_input_port midi_input_device  
 %type <String> string param_val filename engine_name command create_instruction destroy_instruction get_instruction list_instruction load_instruction set_chan_instruction load_instr_args load_engine_args audio_output_type midi_input_type set_instruction subscribe_event unsubscribe_event  
206  %type <FillResponse> buffer_size_type  %type <FillResponse> buffer_size_type
207  %type <KeyValList> key_val_list  %type <KeyValList> key_val_list query_val_list
208    %type <LoadMode> instr_load_mode
209    %type <Bool> modal_arg
210    %type <UniversalPath> path path_base path_prefix path_body
211    
212  %start input  %start input
213    
# Line 76  void yyerror(const char* s); Line 215  void yyerror(const char* s);
215    
216  //TODO: return more meaningful error messages  //TODO: return more meaningful error messages
217    
218  input                 : line LF  /*
219      The LSCP specification document input file (Documentation/lscp.xml) is
220      automatically updated with this file using the scripts/update_grammar.pl
221      script. Do not modify or delete the GRAMMAR_BNF_BEGIN and GRAMMAR_BNF_END
222      lines !
223    */
224    
225    // GRAMMAR_BNF_BEGIN - do NOT delete or modify this line !!!
226    
227  line                  :  /* epsilon (empty line ignored) */ { return LSCP_DONE; }  input                 :  line   { INCREMENT_LINE; if (!$1.empty()) LSCPSERVER->AnswerClient($1); return LSCP_DONE; }
228                        |  comment  { return LSCP_DONE; }                        |  error  { INCREMENT_LINE; LSCPSERVER->AnswerClient("ERR:0:" + sLastError + "\r\n"); RESTART; return LSCP_SYNTAX_ERROR; }
                       |  command  { LSCPSERVER->AnswerClient($1); return LSCP_DONE; }  
                       |  error    { LSCPSERVER->AnswerClient("Err:0:Unknown command.\r\n"); RESTART; return LSCP_SYNTAX_ERROR; }  
229                        ;                        ;
230    
231  comment               :  HASH  line                  :  statement LF     { $$ = $1; }
232                        |  comment HASH                        |  statement CR LF  { $$ = $1; }
                       |  comment SP  
                       |  comment NUMBER  
                       |  comment string  
233                        ;                        ;
234    
235  command               :  ADD SP CHANNEL                             { $$ = LSCPSERVER->AddChannel();                  }  statement             :  /* epsilon (empty statement/line ignored) */  { $$ = ""; }
236                        |  GET SP get_instruction                     { $$ = $3;                                        }                        |  comment  { $$ = ""; }
237                        |  CREATE SP create_instruction               { $$ = $3;                                        }                        |  command
                       |  DESTROY SP destroy_instruction             { $$ = $3;                                        }  
                       |  LIST SP list_instruction                   { $$ = $3;                                        }  
                       |  LOAD SP load_instruction                   { $$ = $3;                                        }  
                       |  REMOVE SP CHANNEL SP sampler_channel       { $$ = LSCPSERVER->RemoveChannel($5);             }  
                       |  SET SP set_instruction                     { $$ = $3;                                        }  
                       |  SUBSCRIBE SP subscribe_event               { $$ = $3;                                        }  
                       |  UNSUBSCRIBE SP unsubscribe_event           { $$ = $3;                                        }  
                       |  RESET SP CHANNEL SP sampler_channel        { $$ = LSCPSERVER->ResetChannel($5);              }  
                       |  QUIT                                       { LSCPSERVER->AnswerClient("Bye!\r\n"); return LSCP_QUIT; }  
                       ;  
   
 subscribe_event       :  CHANNELS                                   { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_channels); }  
                       |  VOICE_COUNT                                { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_voice_count); }  
                       |  STREAM_COUNT                               { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_stream_count); }  
                       |  BUFFER_FILL                                { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_buffer_fill); }  
                       |  INFO                                       { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_info); }  
                       |  MISCELLANEOUS                              { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_misc); }  
                       ;  
   
 unsubscribe_event     :  CHANNELS                                   { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_channels); }  
                       |  VOICE_COUNT                                { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_voice_count); }  
                       |  STREAM_COUNT                               { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_stream_count); }  
                       |  BUFFER_FILL                                { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_buffer_fill); }  
                       |  INFO                                       { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_info); }  
                       |  MISCELLANEOUS                              { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_misc); }  
                       ;  
   
 get_instruction       :  AVAILABLE_ENGINES                          { $$ = LSCPSERVER->GetAvailableEngines();       }  
                       |  AVAILABLE_MIDI_INPUT_DRIVERS               { $$ = LSCPSERVER->GetAvailableMidiInputDrivers();       }  
                       |  MIDI_INPUT_DRIVER SP INFO SP string        { $$ = LSCPSERVER->GetMidiInputDriverInfo($5);       }  
                       |  MIDI_INPUT_DRIVER_PARAMETER SP INFO SP string SP string     { $$ = LSCPSERVER->GetMidiInputDriverParameterInfo($5, $7);       }  
                       |  MIDI_INPUT_DRIVER_PARAMETER SP INFO SP string SP string SP key_val_list    { $$ = LSCPSERVER->GetMidiInputDriverParameterInfo($5, $7, $9);       }  
                       |  AVAILABLE_AUDIO_OUTPUT_DRIVERS                                             { $$ = LSCPSERVER->GetAvailableAudioOutputDrivers();       }  
                       |  AUDIO_OUTPUT_DRIVER SP INFO SP string                                      { $$ = LSCPSERVER->GetAudioOutputDriverInfo($5);       }  
                       |  AUDIO_OUTPUT_DRIVER_PARAMETER SP INFO SP string SP string                  { $$ = LSCPSERVER->GetAudioOutputDriverParameterInfo($5, $7);       }  
                       |  AUDIO_OUTPUT_DRIVER_PARAMETER SP INFO SP string SP string SP key_val_list  { $$ = LSCPSERVER->GetAudioOutputDriverParameterInfo($5, $7, $9);       }  
                       |  AUDIO_OUTPUT_DEVICES                                                       { $$ = LSCPSERVER->GetAudioOutputDeviceCount();       }  
                       |  MIDI_INPUT_DEVICES                                                         { $$ = LSCPSERVER->GetMidiInputDeviceCount();       }  
                       |  AUDIO_OUTPUT_DEVICE SP INFO SP NUMBER                                      { $$ = LSCPSERVER->GetAudioOutputDeviceInfo($5);       }  
                       |  MIDI_INPUT_DEVICE SP INFO SP NUMBER                                        { $$ = LSCPSERVER->GetMidiInputDeviceInfo($5);       }  
                       |  MIDI_INPUT_PORT SP INFO SP NUMBER SP NUMBER                                { $$ = LSCPSERVER->GetMidiInputPortInfo($5, $7);       }  
                       |  MIDI_INPUT_PORT_PARAMETER SP INFO SP NUMBER SP NUMBER SP string            { $$ = LSCPSERVER->GetMidiInputPortParameterInfo($5, $7, $9);       }  
                       |  AUDIO_OUTPUT_CHANNEL SP INFO SP NUMBER SP NUMBER                           { $$ = LSCPSERVER->GetAudioOutputChannelInfo($5, $7);       }  
                       |  AUDIO_OUTPUT_CHANNEL_PARAMETER SP INFO SP NUMBER SP NUMBER SP string       { $$ = LSCPSERVER->GetAudioOutputChannelParameterInfo($5, $7, $9);       }  
                       |  CHANNELS                                                                   { $$ = LSCPSERVER->GetChannels();       }  
                       |  CHANNEL SP INFO SP sampler_channel                                         { $$ = LSCPSERVER->GetChannelInfo($5);       }  
                       |  CHANNEL SP BUFFER_FILL SP buffer_size_type SP sampler_channel              { $$ = LSCPSERVER->GetBufferFill($5, $7);       }  
                       |  CHANNEL SP STREAM_COUNT SP sampler_channel                                 { $$ = LSCPSERVER->GetStreamCount($5);       }  
                       |  CHANNEL SP VOICE_COUNT SP sampler_channel                                  { $$ = LSCPSERVER->GetVoiceCount($5);       }  
                       |  ENGINE SP INFO SP engine_name                                              { $$ = LSCPSERVER->GetEngineInfo($5);       }  
                       ;  
   
 set_instruction       :  AUDIO_OUTPUT_DEVICE_PARAMETER SP NUMBER SP string EQ param_val             { $$ = LSCPSERVER->SetAudioOutputDeviceParameter($3, $5, $7);       }  
                       |  AUDIO_OUTPUT_CHANNEL_PARAMETER SP NUMBER SP NUMBER SP string EQ param_val  { $$ = LSCPSERVER->SetAudioOutputChannelParameter($3, $5, $7, $9);       }  
                       |  MIDI_INPUT_DEVICE_PARAMETER SP NUMBER SP string EQ param_val               { $$ = LSCPSERVER->SetMidiInputDeviceParameter($3, $5, $7);       }  
                       |  MIDI_INPUT_PORT_PARAMETER SP NUMBER SP NUMBER SP string EQ param_val       { $$ = LSCPSERVER->SetMidiInputPortParameter($3, $5, $7, $9);       }  
                       |  CHANNEL SP set_chan_instruction                                            { $$ = $3;                                                         }  
                       ;  
   
 create_instruction    :  AUDIO_OUTPUT_DEVICE SP string SP key_val_list { $$ = LSCPSERVER->CreateAudioOutputDevice($3,$5); }  
                       |  AUDIO_OUTPUT_DEVICE SP string                 { $$ = LSCPSERVER->CreateAudioOutputDevice($3);    }  
                       |  MIDI_INPUT_DEVICE SP string SP key_val_list   { $$ = LSCPSERVER->CreateMidiInputDevice($3,$5);   }  
                       |  MIDI_INPUT_DEVICE SP string                   { $$ = LSCPSERVER->CreateMidiInputDevice($3);      }  
238                        ;                        ;
239    
240  destroy_instruction   :  AUDIO_OUTPUT_DEVICE SP NUMBER  { $$ = LSCPSERVER->DestroyAudioOutputDevice($3);       }  comment               :  '#'
241                        |  MIDI_INPUT_DEVICE SP NUMBER    { $$ = LSCPSERVER->DestroyMidiInputDevice($3);         }                        |  comment '#'
242                          |  comment SP
243                          |  comment number
244                          |  comment string
245                          ;
246    
247    command               :  ADD SP add_instruction                { $$ = $3;                                                }
248                          |  MAP SP map_instruction                { $$ = $3;                                                }
249                          |  UNMAP SP unmap_instruction            { $$ = $3;                                                }
250                          |  GET SP get_instruction                { $$ = $3;                                                }
251                          |  CREATE SP create_instruction          { $$ = $3;                                                }
252                          |  DESTROY SP destroy_instruction        { $$ = $3;                                                }
253                          |  LIST SP list_instruction              { $$ = $3;                                                }
254                          |  LOAD SP load_instruction              { $$ = $3;                                                }
255                          |  REMOVE SP remove_instruction          { $$ = $3;                                                }
256                          |  SET SP set_instruction                { $$ = $3;                                                }
257                          |  SUBSCRIBE SP subscribe_event          { $$ = $3;                                                }
258                          |  UNSUBSCRIBE SP unsubscribe_event      { $$ = $3;                                                }
259                          |  RESET SP reset_instruction            { $$ = $3;                                                }
260                          |  CLEAR SP clear_instruction            { $$ = $3;                                                }
261                          |  FIND SP find_instruction              { $$ = $3;                                                }
262                          |  MOVE SP move_instruction              { $$ = $3;                                                }
263                          |  COPY SP copy_instruction              { $$ = $3;                                                }
264                          |  EDIT SP edit_instruction              { $$ = $3;                                                }
265                          |  FORMAT SP format_instruction          { $$ = $3;                                                }
266                          |  SEND SP send_instruction              { $$ = $3;                                                }
267                          |  APPEND SP append_instruction          { $$ = $3;                                                }
268                          |  INSERT SP insert_instruction          { $$ = $3;                                                }
269                          |  RESET                                 { $$ = LSCPSERVER->ResetSampler();                        }
270                          |  QUIT                                  { LSCPSERVER->AnswerClient("Bye!\r\n"); return LSCP_QUIT; }
271                          ;
272    
273    add_instruction       :  CHANNEL                               { $$ = LSCPSERVER->AddChannel();                  }
274                          |  CHANNEL SP MIDI_INPUT SP sampler_channel SP device_index                           { $$ = LSCPSERVER->AddChannelMidiInput($5,$7);    }
275                          |  CHANNEL SP MIDI_INPUT SP sampler_channel SP device_index SP midi_input_port_index  { $$ = LSCPSERVER->AddChannelMidiInput($5,$7,$9); }
276                          |  DB_INSTRUMENT_DIRECTORY SP db_path    { $$ = LSCPSERVER->AddDbInstrumentDirectory($3);  }
277                          |  DB_INSTRUMENTS SP NON_MODAL SP scan_mode SP db_path SP filename                        { $$ = LSCPSERVER->AddDbInstruments($5,$7,$9, true);        }
278                          |  DB_INSTRUMENTS SP NON_MODAL SP scan_mode SP FILE_AS_DIR SP db_path SP filename         { $$ = LSCPSERVER->AddDbInstruments($5,$9,$11, true, true); }
279                          |  DB_INSTRUMENTS SP scan_mode SP db_path SP filename                                     { $$ = LSCPSERVER->AddDbInstruments($3,$5,$7);              }
280                          |  DB_INSTRUMENTS SP scan_mode SP FILE_AS_DIR SP db_path SP filename                      { $$ = LSCPSERVER->AddDbInstruments($3,$7,$9, false, true); }
281                          |  DB_INSTRUMENTS SP NON_MODAL SP db_path SP filename                                     { $$ = LSCPSERVER->AddDbInstruments($5,$7, -1, true);       }
282                          |  DB_INSTRUMENTS SP NON_MODAL SP db_path SP filename SP instrument_index                 { $$ = LSCPSERVER->AddDbInstruments($5,$7,$9, true);        }
283                          |  DB_INSTRUMENTS SP db_path SP filename                                                  { $$ = LSCPSERVER->AddDbInstruments($3,$5);                 }
284                          |  DB_INSTRUMENTS SP db_path SP filename SP instrument_index                              { $$ = LSCPSERVER->AddDbInstruments($3,$5,$7);              }
285                          |  MIDI_INSTRUMENT_MAP                   { $$ = LSCPSERVER->AddMidiInstrumentMap();                }
286                          |  MIDI_INSTRUMENT_MAP SP map_name       { $$ = LSCPSERVER->AddMidiInstrumentMap($3);              }
287                          |  SEND_EFFECT_CHAIN SP device_index     { $$ = LSCPSERVER->AddSendEffectChain($3);                }
288                          ;
289    
290    subscribe_event       :  AUDIO_OUTPUT_DEVICE_COUNT             { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_audio_device_count);   }
291                          |  AUDIO_OUTPUT_DEVICE_INFO              { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_audio_device_info);    }
292                          |  MIDI_INPUT_DEVICE_COUNT               { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_midi_device_count);    }
293                          |  MIDI_INPUT_DEVICE_INFO                { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_midi_device_info);     }
294                          |  CHANNEL_COUNT                         { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_channel_count);        }
295                          |  CHANNEL_MIDI                          { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_channel_midi);         }
296                          |  DEVICE_MIDI                           { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_device_midi);          }
297                          |  VOICE_COUNT                           { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_voice_count);          }
298                          |  STREAM_COUNT                          { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_stream_count);         }
299                          |  BUFFER_FILL                           { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_buffer_fill);          }
300                          |  CHANNEL_INFO                          { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_channel_info);         }
301                          |  FX_SEND_COUNT                         { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_fx_send_count);        }
302                          |  FX_SEND_INFO                          { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_fx_send_info);         }
303                          |  MIDI_INSTRUMENT_MAP_COUNT             { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_midi_instr_map_count); }
304                          |  MIDI_INSTRUMENT_MAP_INFO              { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_midi_instr_map_info);  }
305                          |  MIDI_INSTRUMENT_COUNT                 { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_midi_instr_count);     }
306                          |  MIDI_INSTRUMENT_INFO                  { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_midi_instr_info);      }
307                          |  DB_INSTRUMENT_DIRECTORY_COUNT         { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_db_instr_dir_count);   }
308                          |  DB_INSTRUMENT_DIRECTORY_INFO          { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_db_instr_dir_info);    }
309                          |  DB_INSTRUMENT_COUNT                   { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_db_instr_count);       }
310                          |  DB_INSTRUMENT_INFO                    { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_db_instr_info);        }
311                          |  DB_INSTRUMENTS_JOB_INFO               { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_db_instrs_job_info);   }
312                          |  MISCELLANEOUS                         { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_misc);                 }
313                          |  TOTAL_STREAM_COUNT                    { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_total_stream_count);   }
314                          |  TOTAL_VOICE_COUNT                     { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_total_voice_count);    }
315                          |  GLOBAL_INFO                           { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_global_info);          }
316                          |  EFFECT_INSTANCE_COUNT                 { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_fx_instance_count);    }
317                          |  EFFECT_INSTANCE_INFO                  { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_fx_instance_info);     }
318                          |  SEND_EFFECT_CHAIN_COUNT               { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_send_fx_chain_count);  }
319                          |  SEND_EFFECT_CHAIN_INFO                { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_send_fx_chain_info);   }
320                          ;
321    
322    unsubscribe_event     :  AUDIO_OUTPUT_DEVICE_COUNT             { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_audio_device_count);   }
323                          |  AUDIO_OUTPUT_DEVICE_INFO              { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_audio_device_info);    }
324                          |  MIDI_INPUT_DEVICE_COUNT               { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_midi_device_count);    }
325                          |  MIDI_INPUT_DEVICE_INFO                { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_midi_device_info);     }
326                          |  CHANNEL_COUNT                         { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_channel_count);        }
327                          |  CHANNEL_MIDI                          { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_channel_midi);         }
328                          |  DEVICE_MIDI                           { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_device_midi);          }
329                          |  VOICE_COUNT                           { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_voice_count);          }
330                          |  STREAM_COUNT                          { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_stream_count);         }
331                          |  BUFFER_FILL                           { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_buffer_fill);          }
332                          |  CHANNEL_INFO                          { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_channel_info);         }
333                          |  FX_SEND_COUNT                         { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_fx_send_count);        }
334                          |  FX_SEND_INFO                          { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_fx_send_info);         }
335                          |  MIDI_INSTRUMENT_MAP_COUNT             { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_midi_instr_map_count); }
336                          |  MIDI_INSTRUMENT_MAP_INFO              { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_midi_instr_map_info);  }
337                          |  MIDI_INSTRUMENT_COUNT                 { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_midi_instr_count);     }
338                          |  MIDI_INSTRUMENT_INFO                  { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_midi_instr_info);      }
339                          |  DB_INSTRUMENT_DIRECTORY_COUNT         { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_db_instr_dir_count);   }
340                          |  DB_INSTRUMENT_DIRECTORY_INFO          { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_db_instr_dir_info);    }
341                          |  DB_INSTRUMENT_COUNT                   { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_db_instr_count);       }
342                          |  DB_INSTRUMENT_INFO                    { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_db_instr_info);        }
343                          |  DB_INSTRUMENTS_JOB_INFO               { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_db_instrs_job_info);   }
344                          |  MISCELLANEOUS                         { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_misc);                 }
345                          |  TOTAL_STREAM_COUNT                    { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_total_stream_count);   }
346                          |  TOTAL_VOICE_COUNT                     { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_total_voice_count);    }
347                          |  GLOBAL_INFO                           { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_global_info);          }
348                          |  EFFECT_INSTANCE_COUNT                 { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_fx_instance_count);    }
349                          |  EFFECT_INSTANCE_INFO                  { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_fx_instance_info);     }
350                          |  SEND_EFFECT_CHAIN_COUNT               { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_send_fx_chain_count);  }
351                          |  SEND_EFFECT_CHAIN_INFO                { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_send_fx_chain_info);   }
352                          ;
353    
354    map_instruction       :  MIDI_INSTRUMENT SP modal_arg midi_map SP midi_bank SP midi_prog SP engine_name SP filename SP instrument_index SP volume_value { $$ = LSCPSERVER->AddOrReplaceMIDIInstrumentMapping($4,$6,$8,$10,$12,$14,$16,MidiInstrumentMapper::DONTCARE,"",$3); }
355                          |  MIDI_INSTRUMENT SP modal_arg midi_map SP midi_bank SP midi_prog SP engine_name SP filename SP instrument_index SP volume_value SP instr_load_mode { $$ = LSCPSERVER->AddOrReplaceMIDIInstrumentMapping($4,$6,$8,$10,$12,$14,$16,$18,"",$3); }
356                          |  MIDI_INSTRUMENT SP modal_arg midi_map SP midi_bank SP midi_prog SP engine_name SP filename SP instrument_index SP volume_value SP entry_name { $$ = LSCPSERVER->AddOrReplaceMIDIInstrumentMapping($4,$6,$8,$10,$12,$14,$16,MidiInstrumentMapper::DONTCARE,$18,$3); }
357                          |  MIDI_INSTRUMENT SP modal_arg midi_map SP midi_bank SP midi_prog SP engine_name SP filename SP instrument_index SP volume_value SP instr_load_mode SP entry_name { $$ = LSCPSERVER->AddOrReplaceMIDIInstrumentMapping($4,$6,$8,$10,$12,$14,$16,$18,$20,$3); }
358                          ;
359    
360    unmap_instruction     :  MIDI_INSTRUMENT SP midi_map SP midi_bank SP midi_prog  { $$ = LSCPSERVER->RemoveMIDIInstrumentMapping($3,$5,$7); }
361                          ;
362    
363    remove_instruction    :  CHANNEL SP sampler_channel                   { $$ = LSCPSERVER->RemoveChannel($3);                      }
364                          |  CHANNEL SP MIDI_INPUT SP sampler_channel                                           { $$ = LSCPSERVER->RemoveChannelMidiInput($5);       }
365                          |  CHANNEL SP MIDI_INPUT SP sampler_channel SP device_index                           { $$ = LSCPSERVER->RemoveChannelMidiInput($5,$7);    }
366                          |  CHANNEL SP MIDI_INPUT SP sampler_channel SP device_index SP midi_input_port_index  { $$ = LSCPSERVER->RemoveChannelMidiInput($5,$7,$9); }
367                          |  MIDI_INSTRUMENT_MAP SP midi_map              { $$ = LSCPSERVER->RemoveMidiInstrumentMap($3);            }
368                          |  MIDI_INSTRUMENT_MAP SP ALL                   { $$ = LSCPSERVER->RemoveAllMidiInstrumentMaps();          }
369                          |  SEND_EFFECT_CHAIN SP device_index SP effect_chain  { $$ = LSCPSERVER->RemoveSendEffectChain($3,$5);     }
370                          |  SEND_EFFECT_CHAIN SP EFFECT SP device_index SP effect_chain SP chain_pos  { $$ = LSCPSERVER->RemoveSendEffectChainEffect($5,$7,$9); }
371                          |  FX_SEND SP EFFECT SP sampler_channel SP fx_send_id  { $$ = LSCPSERVER->SetFxSendEffect($5,$7,-1,-1);    }
372                          |  DB_INSTRUMENT_DIRECTORY SP FORCE SP db_path  { $$ = LSCPSERVER->RemoveDbInstrumentDirectory($5, true);  }
373                          |  DB_INSTRUMENT_DIRECTORY SP db_path           { $$ = LSCPSERVER->RemoveDbInstrumentDirectory($3);        }
374                          |  DB_INSTRUMENT SP db_path                     { $$ = LSCPSERVER->RemoveDbInstrument($3);                 }
375                          ;
376    
377    get_instruction       :  AVAILABLE_ENGINES                                                          { $$ = LSCPSERVER->GetAvailableEngines();                          }
378                          |  AVAILABLE_EFFECTS                                                          { $$ = LSCPSERVER->GetAvailableEffects();                          }
379                          |  EFFECT_INSTANCES                                                           { $$ = LSCPSERVER->GetEffectInstances();                           }
380                          |  EFFECT SP INFO SP effect_index                                             { $$ = LSCPSERVER->GetEffectInfo($5);                              }
381                          |  EFFECT_INSTANCE SP INFO SP effect_instance                                 { $$ = LSCPSERVER->GetEffectInstanceInfo($5);                      }
382                          |  EFFECT_INSTANCE_INPUT_CONTROL SP INFO SP effect_instance SP input_control  { $$ = LSCPSERVER->GetEffectInstanceInputControlInfo($5,$7);       }
383                          |  SEND_EFFECT_CHAINS SP device_index                                         { $$ = LSCPSERVER->GetSendEffectChains($3);                        }
384                          |  SEND_EFFECT_CHAIN SP INFO SP device_index SP effect_chain                  { $$ = LSCPSERVER->GetSendEffectChainInfo($5,$7);                  }
385                          |  AVAILABLE_MIDI_INPUT_DRIVERS                                               { $$ = LSCPSERVER->GetAvailableMidiInputDrivers();                 }
386                          |  MIDI_INPUT_DRIVER SP INFO SP string                                        { $$ = LSCPSERVER->GetMidiInputDriverInfo($5);                     }
387                          |  MIDI_INPUT_DRIVER_PARAMETER SP INFO SP string SP string                    { $$ = LSCPSERVER->GetMidiInputDriverParameterInfo($5, $7);        }
388                          |  MIDI_INPUT_DRIVER_PARAMETER SP INFO SP string SP string SP key_val_list    { $$ = LSCPSERVER->GetMidiInputDriverParameterInfo($5, $7, $9);    }
389                          |  AVAILABLE_AUDIO_OUTPUT_DRIVERS                                             { $$ = LSCPSERVER->GetAvailableAudioOutputDrivers();               }
390                          |  AUDIO_OUTPUT_DRIVER SP INFO SP string                                      { $$ = LSCPSERVER->GetAudioOutputDriverInfo($5);                   }
391                          |  AUDIO_OUTPUT_DRIVER_PARAMETER SP INFO SP string SP string                  { $$ = LSCPSERVER->GetAudioOutputDriverParameterInfo($5, $7);      }
392                          |  AUDIO_OUTPUT_DRIVER_PARAMETER SP INFO SP string SP string SP key_val_list  { $$ = LSCPSERVER->GetAudioOutputDriverParameterInfo($5, $7, $9);  }
393                          |  AUDIO_OUTPUT_DEVICES                                                       { $$ = LSCPSERVER->GetAudioOutputDeviceCount();                    }
394                          |  MIDI_INPUT_DEVICES                                                         { $$ = LSCPSERVER->GetMidiInputDeviceCount();                      }
395                          |  AUDIO_OUTPUT_DEVICE SP INFO SP number                                      { $$ = LSCPSERVER->GetAudioOutputDeviceInfo($5);                   }
396                          |  MIDI_INPUT_DEVICE SP INFO SP number                                        { $$ = LSCPSERVER->GetMidiInputDeviceInfo($5);                     }
397                          |  MIDI_INPUT_PORT SP INFO SP number SP number                                { $$ = LSCPSERVER->GetMidiInputPortInfo($5, $7);                   }
398                          |  MIDI_INPUT_PORT_PARAMETER SP INFO SP number SP number SP string            { $$ = LSCPSERVER->GetMidiInputPortParameterInfo($5, $7, $9);      }
399                          |  AUDIO_OUTPUT_CHANNEL SP INFO SP number SP number                           { $$ = LSCPSERVER->GetAudioOutputChannelInfo($5, $7);              }
400                          |  AUDIO_OUTPUT_CHANNEL_PARAMETER SP INFO SP number SP number SP string       { $$ = LSCPSERVER->GetAudioOutputChannelParameterInfo($5, $7, $9); }
401                          |  CHANNELS                                                                   { $$ = LSCPSERVER->GetChannels();                                  }
402                          |  CHANNEL SP INFO SP sampler_channel                                         { $$ = LSCPSERVER->GetChannelInfo($5);                             }
403                          |  CHANNEL SP BUFFER_FILL SP buffer_size_type SP sampler_channel              { $$ = LSCPSERVER->GetBufferFill($5, $7);                          }
404                          |  CHANNEL SP STREAM_COUNT SP sampler_channel                                 { $$ = LSCPSERVER->GetStreamCount($5);                             }
405                          |  CHANNEL SP VOICE_COUNT SP sampler_channel                                  { $$ = LSCPSERVER->GetVoiceCount($5);                              }
406                          |  ENGINE SP INFO SP engine_name                                              { $$ = LSCPSERVER->GetEngineInfo($5);                              }
407                          |  SERVER SP INFO                                                             { $$ = LSCPSERVER->GetServerInfo();                                }
408                          |  TOTAL_STREAM_COUNT                                                         { $$ = LSCPSERVER->GetTotalStreamCount();                           }
409                          |  TOTAL_VOICE_COUNT                                                          { $$ = LSCPSERVER->GetTotalVoiceCount();                           }
410                          |  TOTAL_VOICE_COUNT_MAX                                                      { $$ = LSCPSERVER->GetTotalVoiceCountMax();                        }
411                          |  MIDI_INSTRUMENTS SP midi_map                                               { $$ = LSCPSERVER->GetMidiInstrumentMappings($3);                  }
412                          |  MIDI_INSTRUMENTS SP ALL                                                    { $$ = LSCPSERVER->GetAllMidiInstrumentMappings();                 }
413                          |  MIDI_INSTRUMENT SP INFO SP midi_map SP midi_bank SP midi_prog              { $$ = LSCPSERVER->GetMidiInstrumentMapping($5,$7,$9);             }
414                          |  MIDI_INSTRUMENT_MAPS                                                       { $$ = LSCPSERVER->GetMidiInstrumentMaps();                        }
415                          |  MIDI_INSTRUMENT_MAP SP INFO SP midi_map                                    { $$ = LSCPSERVER->GetMidiInstrumentMap($5);                       }
416                          |  FX_SENDS SP sampler_channel                                                { $$ = LSCPSERVER->GetFxSends($3);                                 }
417                          |  FX_SEND SP INFO SP sampler_channel SP fx_send_id                           { $$ = LSCPSERVER->GetFxSendInfo($5,$7);                           }
418                          |  DB_INSTRUMENT_DIRECTORIES SP RECURSIVE SP db_path                          { $$ = LSCPSERVER->GetDbInstrumentDirectoryCount($5, true);        }
419                          |  DB_INSTRUMENT_DIRECTORIES SP db_path                                       { $$ = LSCPSERVER->GetDbInstrumentDirectoryCount($3, false);       }
420                          |  DB_INSTRUMENT_DIRECTORY SP INFO SP db_path                                 { $$ = LSCPSERVER->GetDbInstrumentDirectoryInfo($5);               }
421                          |  DB_INSTRUMENTS SP RECURSIVE SP db_path                                     { $$ = LSCPSERVER->GetDbInstrumentCount($5, true);                 }
422                          |  DB_INSTRUMENTS SP db_path                                                  { $$ = LSCPSERVER->GetDbInstrumentCount($3, false);                }
423                          |  DB_INSTRUMENT SP INFO SP db_path                                           { $$ = LSCPSERVER->GetDbInstrumentInfo($5);                        }
424                          |  DB_INSTRUMENTS_JOB SP INFO SP number                                       { $$ = LSCPSERVER->GetDbInstrumentsJobInfo($5);                    }
425                          |  VOLUME                                                                     { $$ = LSCPSERVER->GetGlobalVolume();                              }
426                          |  VOICES                                                                     { $$ = LSCPSERVER->GetGlobalMaxVoices();                           }
427                          |  STREAMS                                                                    { $$ = LSCPSERVER->GetGlobalMaxStreams();                          }
428                          |  FILE SP INSTRUMENTS SP filename                                            { $$ = LSCPSERVER->GetFileInstruments($5);                         }
429                          |  FILE SP INSTRUMENT SP INFO SP filename SP instrument_index                 { $$ = LSCPSERVER->GetFileInstrumentInfo($7,$9);                   }
430                          ;
431    
432    set_instruction       :  AUDIO_OUTPUT_DEVICE_PARAMETER SP number SP string '=' param_val_list             { $$ = LSCPSERVER->SetAudioOutputDeviceParameter($3, $5, $7);      }
433                          |  AUDIO_OUTPUT_CHANNEL_PARAMETER SP number SP number SP string '=' param_val_list  { $$ = LSCPSERVER->SetAudioOutputChannelParameter($3, $5, $7, $9); }
434                          |  MIDI_INPUT_DEVICE_PARAMETER SP number SP string '=' param_val_list               { $$ = LSCPSERVER->SetMidiInputDeviceParameter($3, $5, $7);        }
435                          |  MIDI_INPUT_PORT_PARAMETER SP number SP number SP string '=' NONE                 { $$ = LSCPSERVER->SetMidiInputPortParameter($3, $5, $7, "");      }
436                          |  MIDI_INPUT_PORT_PARAMETER SP number SP number SP string '=' param_val_list       { $$ = LSCPSERVER->SetMidiInputPortParameter($3, $5, $7, $9);      }
437                          |  EFFECT_INSTANCE_INPUT_CONTROL SP VALUE SP effect_instance SP input_control SP control_value  { $$ = LSCPSERVER->SetEffectInstanceInputControlValue($5, $7, $9); }
438                          |  CHANNEL SP set_chan_instruction                                                  { $$ = $3;                                                         }
439                          |  MIDI_INSTRUMENT_MAP SP NAME SP midi_map SP map_name                              { $$ = LSCPSERVER->SetMidiInstrumentMapName($5, $7);               }
440                          |  FX_SEND SP NAME SP sampler_channel SP fx_send_id SP fx_send_name                 { $$ = LSCPSERVER->SetFxSendName($5,$7,$9);                        }
441                          |  FX_SEND SP AUDIO_OUTPUT_CHANNEL SP sampler_channel SP fx_send_id SP audio_channel_index SP audio_channel_index  { $$ = LSCPSERVER->SetFxSendAudioOutputChannel($5,$7,$9,$11); }
442                          |  FX_SEND SP MIDI_CONTROLLER SP sampler_channel SP fx_send_id SP midi_ctrl         { $$ = LSCPSERVER->SetFxSendMidiController($5,$7,$9);              }
443                          |  FX_SEND SP LEVEL SP sampler_channel SP fx_send_id SP volume_value                { $$ = LSCPSERVER->SetFxSendLevel($5,$7,$9);                       }
444                          |  FX_SEND SP EFFECT SP sampler_channel SP fx_send_id SP effect_chain SP chain_pos  { $$ = LSCPSERVER->SetFxSendEffect($5,$7,$9,$11);                  }
445                          |  DB_INSTRUMENT_DIRECTORY SP NAME SP db_path SP stringval_escaped                  { $$ = LSCPSERVER->SetDbInstrumentDirectoryName($5,$7);            }
446                          |  DB_INSTRUMENT_DIRECTORY SP DESCRIPTION SP db_path SP stringval_escaped           { $$ = LSCPSERVER->SetDbInstrumentDirectoryDescription($5,$7);     }
447                          |  DB_INSTRUMENT SP NAME SP db_path SP stringval_escaped                            { $$ = LSCPSERVER->SetDbInstrumentName($5,$7);                     }
448                          |  DB_INSTRUMENT SP DESCRIPTION SP db_path SP stringval_escaped                     { $$ = LSCPSERVER->SetDbInstrumentDescription($5,$7);              }
449                          |  DB_INSTRUMENT SP FILE_PATH SP filename SP filename                               { $$ = LSCPSERVER->SetDbInstrumentFilePath($5,$7);                 }
450                          |  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); }
452                          |  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);                            }
455                          |  VOICES SP number                                                                 { $$ = LSCPSERVER->SetGlobalMaxVoices($3);                         }
456                          |  STREAMS SP number                                                                { $$ = LSCPSERVER->SetGlobalMaxStreams($3);                        }
457                          ;
458    
459    create_instruction    :  AUDIO_OUTPUT_DEVICE SP string SP key_val_list  { $$ = LSCPSERVER->CreateAudioOutputDevice($3,$5); }
460                          |  AUDIO_OUTPUT_DEVICE SP string                  { $$ = LSCPSERVER->CreateAudioOutputDevice($3);    }
461                          |  MIDI_INPUT_DEVICE SP string SP key_val_list    { $$ = LSCPSERVER->CreateMidiInputDevice($3,$5);   }
462                          |  MIDI_INPUT_DEVICE SP string                    { $$ = LSCPSERVER->CreateMidiInputDevice($3);      }
463                          |  FX_SEND SP sampler_channel SP midi_ctrl        { $$ = LSCPSERVER->CreateFxSend($3,$5);            }
464                          |  FX_SEND SP sampler_channel SP midi_ctrl SP fx_send_name  { $$ = LSCPSERVER->CreateFxSend($3,$5,$7); }
465                          |  EFFECT_INSTANCE SP effect_index                { $$ = LSCPSERVER->CreateEffectInstance($3);       }
466                          |  EFFECT_INSTANCE SP effect_system SP module SP effect_name  { $$ = LSCPSERVER->CreateEffectInstance($3,$5,$7); }
467                          ;
468    
469    reset_instruction     :  CHANNEL SP sampler_channel  { $$ = LSCPSERVER->ResetChannel($3); }
470                          ;
471    
472    clear_instruction     :  MIDI_INSTRUMENTS SP midi_map   { $$ = LSCPSERVER->ClearMidiInstrumentMappings($3);  }
473                          |  MIDI_INSTRUMENTS SP ALL        { $$ = LSCPSERVER->ClearAllMidiInstrumentMappings(); }
474                          ;
475    
476    find_instruction      :  DB_INSTRUMENTS SP NON_RECURSIVE SP db_path SP query_val_list              { $$ = LSCPSERVER->FindDbInstruments($5,$7, false);           }
477                          |  DB_INSTRUMENTS SP db_path SP query_val_list                               { $$ = LSCPSERVER->FindDbInstruments($3,$5, true);            }
478                          |  DB_INSTRUMENT_DIRECTORIES SP NON_RECURSIVE SP db_path SP query_val_list   { $$ = LSCPSERVER->FindDbInstrumentDirectories($5,$7, false); }
479                          |  DB_INSTRUMENT_DIRECTORIES SP db_path SP query_val_list                    { $$ = LSCPSERVER->FindDbInstrumentDirectories($3,$5, true);  }
480                          |  LOST SP DB_INSTRUMENT_FILES                                               { $$ = LSCPSERVER->FindLostDbInstrumentFiles();                 }
481                          ;
482    
483    move_instruction      :  DB_INSTRUMENT_DIRECTORY SP db_path SP db_path    { $$ = LSCPSERVER->MoveDbInstrumentDirectory($3,$5); }
484                          |  DB_INSTRUMENT SP db_path SP db_path              { $$ = LSCPSERVER->MoveDbInstrument($3,$5);          }
485                          ;
486    
487    copy_instruction      :  DB_INSTRUMENT_DIRECTORY SP db_path SP db_path    { $$ = LSCPSERVER->CopyDbInstrumentDirectory($3,$5); }
488                          |  DB_INSTRUMENT SP db_path SP db_path              { $$ = LSCPSERVER->CopyDbInstrument($3,$5);          }
489                          ;
490    
491    destroy_instruction   :  AUDIO_OUTPUT_DEVICE SP number  { $$ = LSCPSERVER->DestroyAudioOutputDevice($3); }
492                          |  MIDI_INPUT_DEVICE SP number    { $$ = LSCPSERVER->DestroyMidiInputDevice($3);   }
493                          |  FX_SEND SP sampler_channel SP fx_send_id  { $$ = LSCPSERVER->DestroyFxSend($3,$5); }
494                          |  EFFECT_INSTANCE SP number      { $$ = LSCPSERVER->DestroyEffectInstance($3);    }
495                        ;                        ;
496    
497  load_instruction      :  INSTRUMENT SP load_instr_args  { $$ = $3; }  load_instruction      :  INSTRUMENT SP load_instr_args  { $$ = $3; }
498                        |  ENGINE SP load_engine_args     { $$ = $3; }                        |  ENGINE SP load_engine_args     { $$ = $3; }
499                        ;                        ;
500    
501  set_chan_instruction  :  AUDIO_OUTPUT_DEVICE SP sampler_channel SP audio_output_device                            { $$ = LSCPSERVER->SetAudioOutputDevice($5, $3);      }  append_instruction    :  SEND_EFFECT_CHAIN SP EFFECT SP device_index SP effect_chain SP effect_instance  { $$ = LSCPSERVER->AppendSendEffectChainEffect($5,$7,$9); }
502                        |  AUDIO_OUTPUT_CHANNEL SP sampler_channel SP audio_output_channel SP audio_output_channel  { $$ = LSCPSERVER->SetAudioOutputChannel($5, $7, $3); }                        ;
503                        |  AUDIO_OUTPUT_TYPE SP sampler_channel SP audio_output_type                                { $$ = LSCPSERVER->SetAudioOutputType($5, $3);        }  
504                        |  MIDI_INPUT SP sampler_channel SP midi_input_device SP midi_input_port SP midi_input_channel  { $$ = LSCPSERVER->SetMIDIInput($5, $7, $9, $3);  }  insert_instruction    :  SEND_EFFECT_CHAIN SP EFFECT SP device_index SP effect_chain SP chain_pos SP effect_instance  { $$ = LSCPSERVER->InsertSendEffectChainEffect($5,$7,$9,$11); }
                       |  MIDI_INPUT_DEVICE SP sampler_channel SP midi_input_device                                { $$ = LSCPSERVER->SetMIDIInputDevice($5, $3);        }  
                       |  MIDI_INPUT_PORT SP sampler_channel SP midi_input_port                                    { $$ = LSCPSERVER->SetMIDIInputPort($5, $3);          }  
                       |  MIDI_INPUT_CHANNEL SP sampler_channel SP midi_input_channel                              { $$ = LSCPSERVER->SetMIDIInputChannel($5, $3);       }  
                       |  MIDI_INPUT_TYPE SP sampler_channel SP midi_input_type                                    { $$ = LSCPSERVER->SetMIDIInputType($5, $3);          }  
                       |  VOLUME SP sampler_channel SP volume                                                      { $$ = LSCPSERVER->SetVolume($5, $3);                 }  
505                        ;                        ;
506    
507  key_val_list          :  string EQ param_val                  { $$[$1] = $3;          }  set_chan_instruction  :  AUDIO_OUTPUT_DEVICE SP sampler_channel SP device_index                                              { $$ = LSCPSERVER->SetAudioOutputDevice($5, $3);      }
508                        |  key_val_list SP string EQ param_val  { $$ = $1; $$[$3] = $5; }                        |  AUDIO_OUTPUT_CHANNEL SP sampler_channel SP audio_channel_index SP audio_channel_index               { $$ = LSCPSERVER->SetAudioOutputChannel($5, $7, $3); }
509                          |  AUDIO_OUTPUT_TYPE SP sampler_channel SP audio_output_type_name                                      { $$ = LSCPSERVER->SetAudioOutputType($5, $3);        }
510                          |  MIDI_INPUT SP sampler_channel SP device_index SP midi_input_port_index SP midi_input_channel_index  { $$ = LSCPSERVER->SetMIDIInput($5, $7, $9, $3);      }
511                          |  MIDI_INPUT_DEVICE SP sampler_channel SP device_index                                                { $$ = LSCPSERVER->SetMIDIInputDevice($5, $3);        }
512                          |  MIDI_INPUT_PORT SP sampler_channel SP midi_input_port_index                                         { $$ = LSCPSERVER->SetMIDIInputPort($5, $3);          }
513                          |  MIDI_INPUT_CHANNEL SP sampler_channel SP midi_input_channel_index                                   { $$ = LSCPSERVER->SetMIDIInputChannel($5, $3);       }
514                          |  MIDI_INPUT_TYPE SP sampler_channel SP midi_input_type_name                                          { $$ = LSCPSERVER->SetMIDIInputType($5, $3);          }
515                          |  VOLUME SP sampler_channel SP volume_value                                                           { $$ = LSCPSERVER->SetVolume($5, $3);                 }
516                          |  MUTE SP sampler_channel SP boolean                                                                  { $$ = LSCPSERVER->SetChannelMute($5, $3);            }
517                          |  SOLO SP sampler_channel SP boolean                                                                  { $$ = LSCPSERVER->SetChannelSolo($5, $3);            }
518                          |  MIDI_INSTRUMENT_MAP SP sampler_channel SP midi_map                                                  { $$ = LSCPSERVER->SetChannelMap($3, $5);             }
519                          |  MIDI_INSTRUMENT_MAP SP sampler_channel SP NONE                                                      { $$ = LSCPSERVER->SetChannelMap($3, -1);             }
520                          |  MIDI_INSTRUMENT_MAP SP sampler_channel SP DEFAULT                                                   { $$ = LSCPSERVER->SetChannelMap($3, -2);             }
521                          ;
522    
523    edit_instruction      :  CHANNEL SP INSTRUMENT SP sampler_channel  { $$ = LSCPSERVER->EditSamplerChannelInstrument($5); }
524                          ;
525    
526    format_instruction    :  INSTRUMENTS_DB  { $$ = LSCPSERVER->FormatInstrumentsDb(); }
527                          ;
528    
529    modal_arg             :  /* epsilon (empty argument) */  { $$ = true;  }
530                          |  NON_MODAL SP                    { $$ = false; }
531                          ;
532    
533    key_val_list          :  string '=' param_val_list                  { $$[$1] = $3;          }
534                          |  key_val_list SP string '=' param_val_list  { $$ = $1; $$[$3] = $5; }
535                        ;                        ;
536    
537  buffer_size_type      :  BYTES       { $$ = fill_response_bytes;      }  buffer_size_type      :  BYTES       { $$ = fill_response_bytes;      }
538                        |  PERCENTAGE  { $$ = fill_response_percentage; }                        |  PERCENTAGE  { $$ = fill_response_percentage; }
539                        ;                        ;
540    
541  list_instruction      :  AUDIO_OUTPUT_DEVICES  { $$ = LSCPSERVER->GetAudioOutputDevices();       }  list_instruction      :  AUDIO_OUTPUT_DEVICES                               { $$ = LSCPSERVER->GetAudioOutputDevices();              }
542                        |  MIDI_INPUT_DEVICES    { $$ = LSCPSERVER->GetMidiInputDevices();       }                        |  MIDI_INPUT_DEVICES                                 { $$ = LSCPSERVER->GetMidiInputDevices();                }
543                          |  CHANNELS                                           { $$ = LSCPSERVER->ListChannels();                       }
544                          |  CHANNEL SP MIDI_INPUTS SP sampler_channel          { $$ = LSCPSERVER->ListChannelMidiInputs($5);            }
545                          |  AVAILABLE_ENGINES                                  { $$ = LSCPSERVER->ListAvailableEngines();               }
546                          |  AVAILABLE_EFFECTS                                  { $$ = LSCPSERVER->ListAvailableEffects();               }
547                          |  EFFECT_INSTANCES                                   { $$ = LSCPSERVER->ListEffectInstances();                }
548                          |  SEND_EFFECT_CHAINS SP number                       { $$ = LSCPSERVER->ListSendEffectChains($3);             }
549                          |  AVAILABLE_MIDI_INPUT_DRIVERS                       { $$ = LSCPSERVER->ListAvailableMidiInputDrivers();      }
550                          |  AVAILABLE_AUDIO_OUTPUT_DRIVERS                     { $$ = LSCPSERVER->ListAvailableAudioOutputDrivers();    }
551                          |  MIDI_INSTRUMENTS SP midi_map                       { $$ = LSCPSERVER->ListMidiInstrumentMappings($3);       }
552                          |  MIDI_INSTRUMENTS SP ALL                            { $$ = LSCPSERVER->ListAllMidiInstrumentMappings();      }
553                          |  MIDI_INSTRUMENT_MAPS                               { $$ = LSCPSERVER->ListMidiInstrumentMaps();             }
554                          |  FX_SENDS SP sampler_channel                        { $$ = LSCPSERVER->ListFxSends($3);                      }
555                          |  DB_INSTRUMENT_DIRECTORIES SP RECURSIVE SP db_path  { $$ = LSCPSERVER->GetDbInstrumentDirectories($5, true); }
556                          |  DB_INSTRUMENT_DIRECTORIES SP db_path               { $$ = LSCPSERVER->GetDbInstrumentDirectories($3);       }
557                          |  DB_INSTRUMENTS SP RECURSIVE SP db_path             { $$ = LSCPSERVER->GetDbInstruments($5, true);           }
558                          |  DB_INSTRUMENTS SP db_path                          { $$ = LSCPSERVER->GetDbInstruments($3);                 }
559                          |  FILE SP INSTRUMENTS SP filename                    { $$ = LSCPSERVER->ListFileInstruments($5);              }
560                          ;
561    
562    send_instruction      :  CHANNEL SP MIDI_DATA SP string SP sampler_channel SP number SP number  { $$ = LSCPSERVER->SendChannelMidiData($5, $7, $9, $11); }
563                          ;
564    
565    load_instr_args       :  filename SP instrument_index SP sampler_channel               { $$ = LSCPSERVER->LoadInstrument($1, $3, $5);       }
566                          |  NON_MODAL SP filename SP instrument_index SP sampler_channel  { $$ = LSCPSERVER->LoadInstrument($3, $5, $7, true); }
567                          ;
568    
569    load_engine_args      :  engine_name SP sampler_channel  { $$ = LSCPSERVER->SetEngineType($1, $3); }
570                          ;
571    
572    instr_load_mode       :  ON_DEMAND       { $$ = MidiInstrumentMapper::ON_DEMAND;      }
573                          |  ON_DEMAND_HOLD  { $$ = MidiInstrumentMapper::ON_DEMAND_HOLD; }
574                          |  PERSISTENT      { $$ = MidiInstrumentMapper::PERSISTENT;     }
575                          ;
576    
577    effect_instance           : number
578                              ;
579    
580    device_index              :  number
581                              ;
582    
583    audio_channel_index       :  number
584                              ;
585    
586    audio_output_type_name    :  string
587                              ;
588    
589    midi_input_port_index     :  number
590                              ;
591    
592    midi_input_channel_index  :  number
593                              |  ALL  { $$ = 16; }
594                              ;
595    
596    midi_input_type_name      :  string
597                              ;
598    
599    midi_map                  :  number
600                              ;
601    
602    midi_bank                 :  number
603                              ;
604    
605    midi_prog                 :  number
606                              ;
607    
608    midi_ctrl                 :  number
609                              ;
610    
611    volume_value              :  dotnum
612                              |  number  { $$ = $1; }
613                              ;
614    
615    control_value             :  real
616                              ;
617    
618    sampler_channel           :  number
619                              ;
620    
621    instrument_index          :  number
622                              ;
623    
624    fx_send_id                :  number
625                              ;
626    
627    engine_name               :  string
628                              ;
629    
630    filename                  :  path  {
631                                     #if WIN32
632                                     $$ = $1.toWindows();
633                                     #else
634                                     // assuming POSIX
635                                     $$ = $1.toPosix();
636                                     #endif
637                                 }
638                              ;
639    
640    db_path                   :  path  { $$ = $1.toDbPath(); }
641                              ;
642    
643    map_name                  :  stringval_escaped
644                              ;
645    
646    entry_name                :  stringval_escaped
647                              ;
648    
649    fx_send_name              :  stringval_escaped
650                              ;
651    
652    effect_name               :  stringval_escaped
653                              ;
654    
655    effect_index              :  number
656                              ;
657    
658    effect_chain              :  number
659                              ;
660    
661    chain_pos                 :  number
662                              ;
663    
664    input_control             :  number
665                              ;
666    
667    param_val_list            :  param_val
668                              |  param_val_list','param_val  { $$ = $1 + "," + $3; }
669                              ;
670    
671    //TODO: the re-encapsulation into apostrophes for string and strinval here is a hack, since we need a way for __parse_strings() (DeviceParameters.cpp) to distinguish a comma separated list of strings and a string which contains commas. A clean solution would be to move those parser jobs over here to lscp.y
672    param_val                 :  string            { $$ = "\'" + $1 + "\'"; }
673                              |  stringval         { $$ = "\'" + $1 + "\'"; }
674                              |  number            { std::stringstream ss; ss << "\'" << $1 << "\'"; $$ = ss.str(); }
675                              |  dotnum            { std::stringstream ss; ss << "\'" << $1 << "\'"; $$ = ss.str(); } //TODO: maybe better using 'real' instead of 'number' and 'dotnum' rules
676                              ;
677    
678    query_val_list            :  string '=' query_val                    { $$[$1] = $3;          }
679                              |  query_val_list SP string '=' query_val  { $$ = $1; $$[$3] = $5; }
680                              ;
681    
682    query_val                 :  text_escaped
683                              |  stringval_escaped
684                              ;
685    
686    scan_mode                 :  RECURSIVE      { $$ = "RECURSIVE"; }
687                              |  NON_RECURSIVE  { $$ = "NON_RECURSIVE"; }
688                              |  FLAT           { $$ = "FLAT"; }
689                              ;
690    
691    effect_system             :  string
692                              ;
693    
694    module                    :  filename
695                              ;
696    
697    // GRAMMAR_BNF_END - do NOT delete or modify this line !!!
698    
699    
700    // atomic variable symbol rules
701    
702    boolean               :  number  { $$ = $1; }
703                          |  string  { $$ = -1; }
704                          ;
705    
706    dotnum                :      digits '.' digits  { std::stringstream ss($1 + "." + $3); ss.imbue(std::locale::classic()); ss >> $$; }
707                          |  '+' digits '.' digits  { std::stringstream ss($2 + "." + $4); ss.imbue(std::locale::classic()); ss >> $$; }
708                          |  '-' digits '.' digits  { std::stringstream ss("-" + $2 + "." + $4); ss.imbue(std::locale::classic()); ss >> $$; }
709                          ;
710    
711    real                  :      digits '.' digits  { std::stringstream ss($1 + "." + $3); ss.imbue(std::locale::classic()); ss >> $$; }
712                          |  '+' digits '.' digits  { std::stringstream ss($2 + "." + $4); ss.imbue(std::locale::classic()); ss >> $$; }
713                          |  '-' digits '.' digits  { std::stringstream ss("-" + $2 + "." + $4); ss.imbue(std::locale::classic()); ss >> $$; }
714                          |      digits             { std::stringstream ss($1); ss.imbue(std::locale::classic()); ss >> $$;                  }
715                          |  '+' digits             { std::stringstream ss($2); ss.imbue(std::locale::classic()); ss >> $$;                  }
716                          |  '-' digits             { std::stringstream ss("-" + $2); ss.imbue(std::locale::classic()); ss >> $$;            }
717                          ;
718    
719    
720    digits                :  digit         { $$ = $1;      }
721                          |  digits digit  { $$ = $1 + $2; }
722                          ;
723    
724    digit                 :  '0'  { $$ = '0'; }
725                          |  '1'  { $$ = '1'; }
726                          |  '2'  { $$ = '2'; }
727                          |  '3'  { $$ = '3'; }
728                          |  '4'  { $$ = '4'; }
729                          |  '5'  { $$ = '5'; }
730                          |  '6'  { $$ = '6'; }
731                          |  '7'  { $$ = '7'; }
732                          |  '8'  { $$ = '8'; }
733                          |  '9'  { $$ = '9'; }
734                          ;
735    
736    digit_oct             :  '0'  { $$ = '0'; }
737                          |  '1'  { $$ = '1'; }
738                          |  '2'  { $$ = '2'; }
739                          |  '3'  { $$ = '3'; }
740                          |  '4'  { $$ = '4'; }
741                          |  '5'  { $$ = '5'; }
742                          |  '6'  { $$ = '6'; }
743                          |  '7'  { $$ = '7'; }
744                          ;
745    
746    digit_hex             :  '0'  { $$ = '0'; }
747                          |  '1'  { $$ = '1'; }
748                          |  '2'  { $$ = '2'; }
749                          |  '3'  { $$ = '3'; }
750                          |  '4'  { $$ = '4'; }
751                          |  '5'  { $$ = '5'; }
752                          |  '6'  { $$ = '6'; }
753                          |  '7'  { $$ = '7'; }
754                          |  '8'  { $$ = '8'; }
755                          |  '9'  { $$ = '9'; }
756                          |  'a'  { $$ = 'a'; }
757                          |  'b'  { $$ = 'b'; }
758                          |  'c'  { $$ = 'c'; }
759                          |  'd'  { $$ = 'd'; }
760                          |  'e'  { $$ = 'e'; }
761                          |  'f'  { $$ = 'f'; }
762                          |  'A'  { $$ = 'a'; }
763                          |  'B'  { $$ = 'b'; }
764                          |  'C'  { $$ = 'c'; }
765                          |  'D'  { $$ = 'd'; }
766                          |  'E'  { $$ = 'e'; }
767                          |  'F'  { $$ = 'f'; }
768                          ;
769    
770    number                :  digit       { $$ = atoi(String(1, $1).c_str());      }
771                          |  '1' digits  { $$ = atoi(String(String("1") + $2).c_str()); }
772                          |  '2' digits  { $$ = atoi(String(String("2") + $2).c_str()); }
773                          |  '3' digits  { $$ = atoi(String(String("3") + $2).c_str()); }
774                          |  '4' digits  { $$ = atoi(String(String("4") + $2).c_str()); }
775                          |  '5' digits  { $$ = atoi(String(String("5") + $2).c_str()); }
776                          |  '6' digits  { $$ = atoi(String(String("6") + $2).c_str()); }
777                          |  '7' digits  { $$ = atoi(String(String("7") + $2).c_str()); }
778                          |  '8' digits  { $$ = atoi(String(String("8") + $2).c_str()); }
779                          |  '9' digits  { $$ = atoi(String(String("9") + $2).c_str()); }
780                          ;
781    
782    path                  :  '\'' path_base '\''  { $$ = $2; }
783                          |  '\"' path_base '\"'  { $$ = $2; }
784                          ;
785    
786    path_base             :  path_prefix path_body  { $$ = $1 + $2; }
787                          ;
788    
789    path_prefix           :  '/'                 { $$ = Path();                    }
790                          |  alpha_char ':' '/'  { Path p; p.setDrive($1); $$ = p; }
791                          ;
792    
793    path_body             :  /* epsilon (empty argument) */ { $$ = Path();                           }
794                          |  path_body '/'                  { $$ = $1;                               }
795                          |  path_body text_escaped_base    { Path p; p.appendNode($2); $$ = $1 + p; }
796                          ;
797    
798    stringval             :  '\'' text '\''  { $$ = $2; }
799                          |  '\"' text '\"'  { $$ = $2; }
800                          ;
801    
802    stringval_escaped     :  '\'' text_escaped '\''  { $$ = $2; }
803                          |  '\"' text_escaped '\"'  { $$ = $2; }
804                          ;
805    
806    text                  :  SP           { $$ = " ";      }
807                          |  string
808                          |  text SP      { $$ = $1 + " "; }
809                          |  text string  { $$ = $1 + $2;  }
810                          ;
811    
812    // like text_escaped, but missing the slash ('/') character
813    text_escaped_base     :  SP                                { $$ = " ";      }
814                          |  string_escaped
815                          |  text_escaped_base SP              { $$ = $1 + " "; }
816                          |  text_escaped_base string_escaped  { $$ = $1 + $2;  }
817                          ;
818    
819    text_escaped          :  '/'                              { $$ = "/";      }
820                          |  text_escaped_base
821                          |  text_escaped '/'                 { $$ = $1 + "/"; }
822                          |  text_escaped text_escaped_base   { $$ = $1 + $2;  }
823                          ;
824    
825    string                :  char          { std::string s; s = $1; $$ = s; }
826                          |  string char   { $$ = $1 + $2;                  }
827                          ;
828    
829    string_escaped        :  char_base                   { std::string s; s = $1; $$ = s; }
830                          |  escape_seq                  { std::string s; s = $1; $$ = s; }
831                          |  string_escaped char_base    { $$ = $1 + $2;                  }
832                          |  string_escaped escape_seq   { $$ = $1 + $2;                  }
833                          ;
834    
835    // full ASCII character set except space, quotation mark and apostrophe
836    char                  :  char_base
837                          |  '\\'  { $$ = '\\'; }
838                          |  '/'   { $$ = '/';  }
839                          ;
840    
841    // characters A..Z and a..z
842    alpha_char            :  'A' { $$ = 'A'; } | 'B' { $$ = 'B'; } | 'C' { $$ = 'C'; } | 'D' { $$ = 'D'; } | 'E' { $$ = 'E'; } | 'F' { $$ = 'F'; } | 'G' { $$ = 'G'; } | 'H' { $$ = 'H'; } | 'I' { $$ = 'I'; } | 'J' { $$ = 'J'; } | 'K' { $$ = 'K'; } | 'L' { $$ = 'L'; } | 'M' { $$ = 'M'; } | 'N' { $$ = 'N'; } | 'O' { $$ = 'O'; } | 'P' { $$ = 'P'; } | 'Q' { $$ = 'Q'; } | 'R' { $$ = 'R'; } | 'S' { $$ = 'S'; } | 'T' { $$ = 'T'; } | 'U' { $$ = 'U'; } | 'V' { $$ = 'V'; } | 'W' { $$ = 'W'; } | 'X' { $$ = 'X'; } | 'Y' { $$ = 'Y'; } | 'Z' { $$ = 'Z'; }
843                          |  'a' { $$ = 'a'; } | 'b' { $$ = 'b'; } | 'c' { $$ = 'c'; } | 'd' { $$ = 'd'; } | 'e' { $$ = 'e'; } | 'f' { $$ = 'f'; } | 'g' { $$ = 'g'; } | 'h' { $$ = 'h'; } | 'i' { $$ = 'i'; } | 'j' { $$ = 'j'; } | 'k' { $$ = 'k'; } | 'l' { $$ = 'l'; } | 'm' { $$ = 'm'; } | 'n' { $$ = 'n'; } | 'o' { $$ = 'o'; } | 'p' { $$ = 'p'; } | 'q' { $$ = 'q'; } | 'r' { $$ = 'r'; } | 's' { $$ = 's'; } | 't' { $$ = 't'; } | 'u' { $$ = 'u'; } | 'v' { $$ = 'v'; } | 'w' { $$ = 'w'; } | 'x' { $$ = 'x'; } | 'y' { $$ = 'y'; } | 'z' { $$ = 'z'; }
844                          ;
845    
846    // ASCII characters except space, quotation mark, apostrophe, backslash and slash
847    char_base             :  alpha_char
848                          |  '0' { $$ = '0'; } | '1' { $$ = '1'; } | '2' { $$ = '2'; } | '3' { $$ = '3'; } | '4' { $$ = '4'; } | '5' { $$ = '5'; } | '6' { $$ = '6'; } | '7' { $$ = '7'; } | '8' { $$ = '8'; } | '9' { $$ = '9'; }
849                          |  '!' { $$ = '!'; } | '#' { $$ = '#'; } | '$' { $$ = '$'; } | '%' { $$ = '%'; } | '&' { $$ = '&'; } | '(' { $$ = '('; } | ')' { $$ = ')'; } | '*' { $$ = '*'; } | '+' { $$ = '+'; } | '-' { $$ = '-'; } | '.' { $$ = '.'; } | ',' { $$ = ','; }
850                          |  ':' { $$ = ':'; } | ';' { $$ = ';'; } | '<' { $$ = '<'; } | '=' { $$ = '='; } | '>' { $$ = '>'; } | '?' { $$ = '?'; } | '@' { $$ = '@'; }
851                          |  '[' { $$ = '['; } | ']' { $$ = ']'; } | '^' { $$ = '^'; } | '_' { $$ = '_'; }
852                          |  '{' { $$ = '{'; } | '|' { $$ = '|'; } | '}' { $$ = '}'; } | '~' { $$ = '~'; }
853                          |  EXT_ASCII_CHAR
854                          ;
855    
856    escape_seq            :  '\\' '\''  { $$ = '\''; }
857                          |  '\\' '\"'  { $$ = '\"'; }
858                          |  '\\' '\\'  { $$ = '\\'; }
859                          |  '\\' '/'   { $$ = '/';  }
860                          |  '\\' 'n'   { $$ = '\n'; }
861                          |  '\\' 'r'   { $$ = '\r'; }
862                          |  '\\' 'f'   { $$ = '\f'; }
863                          |  '\\' 't'   { $$ = '\t'; }
864                          |  '\\' 'v'   { $$ = '\v'; }
865                          |  escape_seq_octal
866                          |  escape_seq_hex
867                          ;
868    
869    escape_seq_octal      :  '\\' digit_oct                      { $$ = (char) octalsToNumber($2);       }
870                          |  '\\' digit_oct digit_oct            { $$ = (char) octalsToNumber($3,$2);    }
871                          |  '\\' digit_oct digit_oct digit_oct  { $$ = (char) octalsToNumber($4,$3,$2); }
872                          ;
873    
874    escape_seq_hex        :  '\\' 'x' digit_hex            { $$ = (char) hexsToNumber($3);    }
875                          |  '\\' 'x' digit_hex digit_hex  { $$ = (char) hexsToNumber($4,$3); }
876                          ;
877    
878    // rules which are more or less just terminal symbols
879    
880    SP                    :  ' '
881                          ;
882    
883    LF                    :  '\n'
884                          ;
885    
886    CR                    :  '\r'
887                          ;
888    
889    ADD                   :  'A''D''D'
890                          ;
891    
892    GET                   :  'G''E''T'
893                          ;
894    
895    MAP                   :  'M''A''P'
896                          ;
897    
898    UNMAP                 :  'U''N''M''A''P'
899                          ;
900    
901    CLEAR                 :  'C''L''E''A''R'
902                          ;
903    
904    FIND                  :  'F''I''N''D'
905                          ;
906    
907    FILE_AS_DIR           :  'F''I''L''E''_''A''S''_''D''I''R'
908                          ;
909    
910    MOVE                  :  'M''O''V''E'
911                          ;
912    
913    COPY                  :  'C''O''P''Y'
914                          ;
915    
916    CREATE                :  'C''R''E''A''T''E'
917                          ;
918    
919    DESTROY               :  'D''E''S''T''R''O''Y'
920                          ;
921    
922    LIST                  :  'L''I''S''T'
923                          ;
924    
925    LOAD                  :  'L''O''A''D'
926                          ;
927    
928    ALL                   :  'A''L''L'
929                          ;
930    
931    NONE                  :  'N''O''N''E'
932                          ;
933    
934    DEFAULT               :  'D''E''F''A''U''L''T'
935                          ;
936    
937    NON_MODAL             :  'N''O''N''_''M''O''D''A''L'
938                          ;
939    
940    REMOVE                :  'R''E''M''O''V''E'
941                          ;
942    
943    SET                   :  'S''E''T'
944                          ;
945    
946    SHELL                 :  'S''H''E''L''L'
947                          ;
948    
949    INTERACT              :  'I''N''T''E''R''A''C''T'
950                          ;
951    
952    AUTO_CORRECT          :  'A''U''T''O''_''C''O''R''R''E''C''T'
953                          ;
954    
955    APPEND                :  'A''P''P''E''N''D'
956                          ;
957    
958    INSERT                :  'I''N''S''E''R''T'
959                          ;
960    
961    SUBSCRIBE             :  'S''U''B''S''C''R''I''B''E'
962                          ;
963    
964    UNSUBSCRIBE           :  'U''N''S''U''B''S''C''R''I''B''E'
965                          ;
966    
967    CHANNEL               :  'C''H''A''N''N''E''L'
968                          ;
969    
970    AVAILABLE_ENGINES     :  'A''V''A''I''L''A''B''L''E''_''E''N''G''I''N''E''S'
971                          ;
972    
973    AVAILABLE_AUDIO_OUTPUT_DRIVERS  :  'A''V''A''I''L''A''B''L''E''_''A''U''D''I''O''_''O''U''T''P''U''T''_''D''R''I''V''E''R''S'
974                                    ;
975    
976    CHANNELS             :  'C''H''A''N''N''E''L''S'
977                         ;
978    
979    INFO                 :  'I''N''F''O'
980                         ;
981    
982    AUDIO_OUTPUT_DEVICE_COUNT :  'A''U''D''I''O''_''O''U''T''P''U''T''_''D''E''V''I''C''E''_''C''O''U''N''T'
983                              ;
984    
985    AUDIO_OUTPUT_DEVICE_INFO  :  'A''U''D''I''O''_''O''U''T''P''U''T''_''D''E''V''I''C''E''_''I''N''F''O'
986                              ;
987    
988    MIDI_INPUT_DEVICE_COUNT   :  'M''I''D''I''_''I''N''P''U''T''_''D''E''V''I''C''E''_''C''O''U''N''T'
989                              ;
990    
991    MIDI_INPUT_DEVICE_INFO    :  'M''I''D''I''_''I''N''P''U''T''_''D''E''V''I''C''E''_''I''N''F''O'
992                              ;
993    
994    MIDI_INSTRUMENT_MAP_COUNT :  'M''I''D''I''_''I''N''S''T''R''U''M''E''N''T''_''M''A''P''_''C''O''U''N''T'
995                              ;
996    
997    MIDI_INSTRUMENT_MAP_INFO  :  'M''I''D''I''_''I''N''S''T''R''U''M''E''N''T''_''M''A''P''_''I''N''F''O'
998                              ;
999    
1000    MIDI_INSTRUMENT_COUNT     :  'M''I''D''I''_''I''N''S''T''R''U''M''E''N''T''_''C''O''U''N''T'
1001                              ;
1002    
1003    MIDI_INSTRUMENT_INFO      :  'M''I''D''I''_''I''N''S''T''R''U''M''E''N''T''_''I''N''F''O'
1004                              ;
1005    
1006    DB_INSTRUMENT_DIRECTORY_COUNT :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''D''I''R''E''C''T''O''R''Y''_''C''O''U''N''T'
1007                                  ;
1008    
1009    DB_INSTRUMENT_DIRECTORY_INFO  :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''D''I''R''E''C''T''O''R''Y''_''I''N''F''O'
1010                                  ;
1011    
1012    DB_INSTRUMENT_COUNT           :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''C''O''U''N''T'
1013                                  ;
1014    
1015    DB_INSTRUMENT_INFO            :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''I''N''F''O'
1016                                  ;
1017    
1018    DB_INSTRUMENT_FILES           :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''F''I''L''E''S'
1019                                  ;
1020    
1021    DB_INSTRUMENTS_JOB_INFO       :  'D''B''_''I''N''S''T''R''U''M''E''N''T''S''_''J''O''B''_''I''N''F''O'
1022                                  ;
1023    
1024    CHANNEL_COUNT        :  'C''H''A''N''N''E''L''_''C''O''U''N''T'
1025                         ;
1026    
1027    CHANNEL_MIDI         :  'C''H''A''N''N''E''L''_''M''I''D''I'
1028                         ;
1029    
1030    DEVICE_MIDI          :  'D''E''V''I''C''E''_''M''I''D''I'
1031                         ;
1032    
1033    CHANNEL_INFO         :  'C''H''A''N''N''E''L''_''I''N''F''O'
1034                         ;
1035    
1036    FX_SEND_COUNT        :  'F''X''_''S''E''N''D''_''C''O''U''N''T'
1037                         ;
1038    
1039    FX_SEND_INFO         :  'F''X''_''S''E''N''D''_''I''N''F''O'
1040                         ;
1041    
1042    BUFFER_FILL          :  'B''U''F''F''E''R''_''F''I''L''L'
1043                         ;
1044    
1045    STREAM_COUNT         :  'S''T''R''E''A''M''_''C''O''U''N''T'
1046                         ;
1047    
1048    VOICE_COUNT          :  'V''O''I''C''E''_''C''O''U''N''T'
1049                         ;
1050    
1051    TOTAL_STREAM_COUNT   :  'T''O''T''A''L''_''S''T''R''E''A''M''_''C''O''U''N''T'
1052                         ;
1053    
1054    TOTAL_VOICE_COUNT    :  'T''O''T''A''L''_''V''O''I''C''E''_''C''O''U''N''T'
1055                         ;
1056    
1057    TOTAL_VOICE_COUNT_MAX:  'T''O''T''A''L''_''V''O''I''C''E''_''C''O''U''N''T''_''M''A''X'
1058                         ;
1059    
1060    GLOBAL_INFO          :  'G''L''O''B''A''L''_''I''N''F''O'
1061                         ;
1062    
1063    EFFECT_INSTANCE_COUNT   :  'E''F''F''E''C''T''_''I''N''S''T''A''N''C''E''_''C''O''U''N''T'
1064                            ;
1065    
1066    EFFECT_INSTANCE_INFO    :  'E''F''F''E''C''T''_''I''N''S''T''A''N''C''E''_''I''N''F''O'
1067                            ;
1068    
1069    SEND_EFFECT_CHAIN_COUNT :  'S''E''N''D''_''E''F''F''E''C''T''_''C''H''A''I''N''_''C''O''U''N''T'
1070                            ;
1071    
1072    SEND_EFFECT_CHAIN_INFO  :  'S''E''N''D''_''E''F''F''E''C''T''_''C''H''A''I''N''_''I''N''F''O'
1073                            ;
1074    
1075    INSTRUMENT           :  'I''N''S''T''R''U''M''E''N''T'
1076                         ;
1077    
1078    INSTRUMENTS          :  'I''N''S''T''R''U''M''E''N''T''S'
1079                         ;
1080    
1081    ENGINE               :  'E' 'N' 'G' 'I' 'N' 'E'
1082                         ;
1083    
1084    ON_DEMAND            :  'O''N''_''D''E''M''A''N''D'
1085                         ;
1086    
1087    ON_DEMAND_HOLD       :  'O''N''_''D''E''M''A''N''D''_''H''O''L''D'
1088                         ;
1089    
1090    PERSISTENT           :  'P''E''R''S''I''S''T''E''N''T'
1091                         ;
1092    
1093    AUDIO_OUTPUT_DEVICE_PARAMETER  :  'A''U''D''I''O''_''O''U''T''P''U''T''_''D''E''V''I''C''E''_''P''A''R''A''M''E''T''E''R'
1094                                   ;
1095    
1096    AUDIO_OUTPUT_DEVICES  :  'A''U''D''I''O''_''O''U''T''P''U''T''_''D''E''V''I''C''E''S'
1097                          ;
1098    
1099    AUDIO_OUTPUT_DEVICE   :  'A''U''D''I''O''_''O''U''T''P''U''T''_''D''E''V''I''C''E'
1100                          ;
1101    
1102    AUDIO_OUTPUT_DRIVER_PARAMETER  :  'A''U''D''I''O''_''O''U''T''P''U''T''_''D''R''I''V''E''R''_''P''A''R''A''M''E''T''E''R'
1103                                   ;
1104    
1105    AUDIO_OUTPUT_DRIVER   :  'A''U''D''I''O''_''O''U''T''P''U''T''_''D''R''I''V''E''R'
1106                          ;
1107    
1108    AUDIO_OUTPUT_CHANNEL_PARAMETER  :  'A''U''D''I''O''_''O''U''T''P''U''T''_''C''H''A''N''N''E''L''_''P''A''R''A''M''E''T''E''R'
1109                                    ;
1110    
1111    AUDIO_OUTPUT_CHANNEL  :  'A''U''D''I''O''_''O''U''T''P''U''T''_''C''H''A''N''N''E''L'
1112                          ;
1113    
1114    AUDIO_OUTPUT_TYPE     :  'A''U''D''I''O''_''O''U''T''P''U''T''_''T''Y''P''E'
1115                          ;
1116    
1117    AVAILABLE_EFFECTS :  'A''V''A''I''L''A''B''L''E''_''E''F''F''E''C''T''S'
1118                      ;
1119    
1120    EFFECT :  'E''F''F''E''C''T'
1121           ;
1122    
1123    EFFECT_INSTANCE :  'E''F''F''E''C''T''_''I''N''S''T''A''N''C''E'
1124                    ;
1125    
1126    EFFECT_INSTANCES :  'E''F''F''E''C''T''_''I''N''S''T''A''N''C''E''S'
1127                     ;
1128    
1129    EFFECT_INSTANCE_INPUT_CONTROL :  'E''F''F''E''C''T''_''I''N''S''T''A''N''C''E''_''I''N''P''U''T''_''C''O''N''T''R''O''L'
1130                                  ;
1131    
1132    SEND_EFFECT_CHAIN :  'S''E''N''D''_''E''F''F''E''C''T''_''C''H''A''I''N'
1133                      ;
1134    
1135    SEND_EFFECT_CHAINS :  'S''E''N''D''_''E''F''F''E''C''T''_''C''H''A''I''N''S'
1136                       ;
1137    
1138    AVAILABLE_MIDI_INPUT_DRIVERS  :  'A''V''A''I''L''A''B''L''E''_''M''I''D''I''_''I''N''P''U''T''_''D''R''I''V''E''R''S'
1139                                  ;
1140    
1141    MIDI_INPUT_DEVICE_PARAMETER  :  'M''I''D''I''_''I''N''P''U''T''_''D''E''V''I''C''E''_''P''A''R''A''M''E''T''E''R'
1142                                 ;
1143    
1144    MIDI_INPUT_PORT_PARAMETER    :  'M''I''D''I''_''I''N''P''U''T''_''P''O''R''T''_''P''A''R''A''M''E''T''E''R'
1145                                 ;
1146    
1147    MIDI_INPUT_DEVICES   :  'M''I''D''I''_''I''N''P''U''T''_''D''E''V''I''C''E''S'
1148                         ;
1149    
1150    MIDI_INPUT_DEVICE     :  'M''I''D''I''_''I''N''P''U''T''_''D''E''V''I''C''E'
1151                          ;
1152    
1153    MIDI_INPUT_DRIVER_PARAMETER  :  'M''I''D''I''_''I''N''P''U''T''_''D''R''I''V''E''R''_''P''A''R''A''M''E''T''E''R'
1154                                 ;
1155    
1156    MIDI_INSTRUMENT  :  'M''I''D''I''_''I''N''S''T''R''U''M''E''N''T'
1157                     ;
1158    
1159    MIDI_INSTRUMENTS  :  'M''I''D''I''_''I''N''S''T''R''U''M''E''N''T''S'
1160                      ;
1161    
1162    MIDI_INSTRUMENT_MAP  :  'M''I''D''I''_''I''N''S''T''R''U''M''E''N''T''_''M''A''P'
1163                         ;
1164    
1165    MIDI_INSTRUMENT_MAPS  :  'M''I''D''I''_''I''N''S''T''R''U''M''E''N''T''_''M''A''P''S'
1166                          ;
1167    
1168    MIDI_INPUT_DRIVER     :  'M''I''D''I''_''I''N''P''U''T''_''D''R''I''V''E''R'
1169                          ;
1170    
1171    MIDI_INPUT_PORT       :  'M''I''D''I''_''I''N''P''U''T''_''P''O''R''T'
1172                          ;
1173    
1174    MIDI_INPUT_CHANNEL    :  'M''I''D''I''_''I''N''P''U''T''_''C''H''A''N''N''E''L'
1175                          ;
1176    
1177    MIDI_INPUT_TYPE       :  'M''I''D''I''_''I''N''P''U''T''_''T''Y''P''E'
1178                          ;
1179    
1180    MIDI_INPUT            :  'M''I''D''I''_''I''N''P''U''T'
1181                          ;
1182    
1183    MIDI_INPUTS           :  'M''I''D''I''_''I''N''P''U''T''S'
1184                          ;
1185    
1186    MIDI_CONTROLLER       :  'M''I''D''I''_''C''O''N''T''R''O''L''L''E''R'
1187                          ;
1188    
1189    SEND                  :  'S''E''N''D'
1190                          ;
1191    
1192    FX_SEND               :  'F''X''_''S''E''N''D'
1193                          ;
1194    
1195    FX_SENDS              :  'F''X''_''S''E''N''D''S'
1196                          ;
1197    
1198    DB_INSTRUMENT_DIRECTORY    :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''D''I''R''E''C''T''O''R''Y'
1199                               ;
1200    
1201    DB_INSTRUMENT_DIRECTORIES  :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''D''I''R''E''C''T''O''R''I''E''S'
1202                               ;
1203    
1204    DB_INSTRUMENTS             :  'D''B''_''I''N''S''T''R''U''M''E''N''T''S'
1205                               ;
1206    
1207    DB_INSTRUMENT              :  'D''B''_''I''N''S''T''R''U''M''E''N''T'
1208                               ;
1209    
1210    DB_INSTRUMENTS_JOB         :  'D''B''_''I''N''S''T''R''U''M''E''N''T''S''_''J''O''B'
1211                               ;
1212    
1213    INSTRUMENTS_DB             :  'I''N''S''T''R''U''M''E''N''T''S''_''D''B'
1214                               ;
1215    
1216    DESCRIPTION                :  'D''E''S''C''R''I''P''T''I''O''N'
1217                               ;
1218    
1219    FORCE                      :  'F''O''R''C''E'
1220                               ;
1221    
1222    FLAT                       :  'F''L''A''T'
1223                               ;
1224    
1225    RECURSIVE                  :  'R''E''C''U''R''S''I''V''E'
1226                               ;
1227    
1228    NON_RECURSIVE              :  'N''O''N''_''R''E''C''U''R''S''I''V''E'
1229                               ;
1230    
1231    LOST                       :  'L''O''S''T'
1232                               ;
1233    
1234    FILE_PATH                  :  'F''I''L''E''_''P''A''T''H'
1235                               ;
1236    
1237    SERVER                :  'S''E''R''V''E''R'
1238                          ;
1239    
1240    VOLUME                :  'V''O''L''U''M''E'
1241                          ;
1242    
1243    LEVEL                 :  'L''E''V''E''L'
1244                          ;
1245    
1246    VALUE                 :  'V''A''L''U''E'
1247                        ;                        ;
1248    
1249  load_instr_args       :  filename SP instrument_index SP sampler_channel  { $$ = LSCPSERVER->LoadInstrument($1, $3, $5);       }  MUTE                  :  'M''U''T''E'
                       |  NON_MODAL SP filename SP instrument_index SP sampler_channel  { $$ = LSCPSERVER->LoadInstrument($3, $5, $7, true);       }  
1250                        ;                        ;
1251    
1252  load_engine_args      :  engine_name SP sampler_channel  { $$ = LSCPSERVER->LoadEngine($1, $3);       }  SOLO                  :  'S''O''L''O'
1253                        ;                        ;
1254    
1255  audio_output_device   :  NUMBER  VOICES                :  'V''O''I''C''E''S'
1256                        ;                        ;
1257    
1258  audio_output_channel  :  NUMBER  STREAMS               :  'S''T''R''E''A''M''S'
1259                        ;                        ;
1260    
1261  audio_output_type     :  string  BYTES                 :  'B''Y''T''E''S'
1262                        ;                        ;
1263    
1264  midi_input_device     :  NUMBER  PERCENTAGE            :  'P''E''R''C''E''N''T''A''G''E'
1265                        ;                        ;
1266    
1267  midi_input_port       :  NUMBER  FILE                  :  'F''I''L''E'
1268                        ;                        ;
1269    
1270  midi_input_channel    :  NUMBER  EDIT                  :  'E''D''I''T'
1271                        ;                        ;
1272    
1273  midi_input_type       :  string  FORMAT                :  'F''O''R''M''A''T'
1274                        ;                        ;
1275    
1276  volume                :  DOTNUM  MIDI_DATA             :  'M''I''D''I''_''D''A''T''A'
                       |  NUMBER  { $$ = $1; }  
1277                        ;                        ;
1278    
1279  sampler_channel       :  NUMBER  RESET                 :  'R''E''S''E''T'
1280                        ;                        ;
1281    
1282  instrument_index      :  NUMBER  MISCELLANEOUS         :  'M''I''S''C''E''L''L''A''N''E''O''U''S'
1283                        ;                        ;
1284    
1285  engine_name           :  string  NAME                  :  'N''A''M''E'
1286                        ;                        ;
1287    
1288  filename              :  STRINGVAL  ECHO                  :  'E''C''H''O'
1289                        ;                        ;
1290    
1291  param_val             :  STRINGVAL                { $$ = $1;                                             }  DOC                   :  'D''O''C'
                       |  NUMBER                   { std::stringstream ss; ss << $1; $$ = ss.str();       }  
                       |  DOTNUM                   { std::stringstream ss; ss << $1; $$ = ss.str();       }  
1292                        ;                        ;
1293    
1294  string                :  CHAR          { std::string s; s = $1; $$ = s; }  QUIT                  :  'Q''U''I''T'
                       |  string CHAR   { $$ = $1 + $2;                  }  
1295                        ;                        ;
1296    
1297  %%  %%
1298    
1299    // 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
1300    
1301  /**  /**
1302   * Will be called when an error occured (usually syntax error).   * Additional informations of a grammar symbol.
1303   */   */
1304  void yyerror(const char* s) {  struct BisonSymbolInfo {
1305      dmsg(2,("LSCPParser: %s\n", s));      bool isTerminalSymbol; ///< Whether the symbol is a terminal or non-termianl symbol. NOTE: Read comment regarding this in _isRuleTerminalSymbol() !!
1306        String nextExpectedChars; ///< According to current parser position: sequence of characters expected next for satisfying this grammar symbol.
1307    };
1308    
1309    #if HAVE_BISON_MAJ >= 3 || !defined(HAVE_BISON_MAJ) // Bison 3.x or younger ...
1310    
1311    /**
1312     * Must ONLY be called just before a so called "reduce" parser action:
1313     * Returns true if the grammar rule, which is just about to be "reduced", is a
1314     * terminal symbol (in *our* terms).
1315     *
1316     * Please note that the term "terminal symbol" is a bit confusingly used in
1317     * this source code here around. In Bison's terms, "terminal symbols" are (more
1318     * or less) just the numbers returned by the YYLEX function. Since we decided
1319     * though to use a convenient solution without a separate lexer, and all its
1320     * caveats, all numbers by the yylex() function here are just the ASCII
1321     * numbers of the individual characters received. Based on that however, one
1322     * single character is not what one would intuitively expect of being a
1323     * "terminal symbol", because it is simply too primitive.
1324     *
1325     * So in this LSCP parser source code a "terminal symbol" rather means a
1326     * keyword like "CREATE" or "GET". In the grammal definition above, those are
1327     * however defined as grammar rules (non-terminals in Bison's terms). So this
1328     * function decides like this: if the given grammar rule just contains
1329     * individual characters on the right side of its grammar rule, then it is a
1330     * "terminal symbol" in *our* terms.
1331     *
1332     * @param rule - Bison grammar rule number
1333     * @param stack - reflecting current Bison parser state
1334     */
1335    inline static bool _isRuleTerminalSymbol(int rule, const std::vector<YYTYPE_INT16>& stack) {
1336        int nrhs = yyr2[rule];
1337        for (int i = 0; i < nrhs; ++i)
1338            if (yystos[*(stack.end() - nrhs + i)] >= YYNTOKENS) return false;
1339        return true;
1340  }  }
1341    
1342  /**  /**
1343   * Clears input buffer and restarts scanner.   * Must ONLY be called just before a so called "reduce" parser action: Returns
1344     * additional informations to the given grammar rule that is about to be
1345     * "reduced".
1346     *
1347     * @param rule - Bison grammar rule number
1348     * @param stack - reflecting current Bison parser state
1349     * @param nextExpectedChars - must already be filled with the characters
1350     *                            expected to be coming next
1351     */
1352    inline static BisonSymbolInfo _symbolInfoForRule(int rule, const std::vector<YYTYPE_INT16>& stack, const String& nextExpectedChars) {
1353        BisonSymbolInfo info;
1354        info.isTerminalSymbol = _isRuleTerminalSymbol(rule, stack);
1355        if (info.isTerminalSymbol) info.nextExpectedChars  = nextExpectedChars;
1356        return info;
1357    }
1358    
1359    #else // Bison 2.x or older ...
1360    
1361    //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).
1362    
1363    /**
1364     * Returns true if the given grammar @a rule is a terminal symbol (in *our*
1365     * terms).
1366     *
1367     * Please note that the term "terminal symbol" is a bit confusingly used in
1368     * this source code here around. In Bison's terms, "terminal symbols" are (more
1369     * or less) just the numbers returned by the YYLEX function. Since we decided
1370     * though to use a convenient solution without a separate lexer, and all its
1371     * caveats, all numbers by the yylex() function here are just the ASCII
1372     * numbers of the individual characters received. Based on that however, one
1373     * single character is not what one would intuitively expect of being a
1374     * "terminal symbol", because it is simply too primitive.
1375     *
1376     * So in this LSCP parser source code a "terminal symbol" rather means a
1377     * keyword like "CREATE" or "GET". In the grammal definition above, those are
1378     * however defined as grammar rules (non-terminals in Bison's terms). So this
1379     * function decides like this: if the given grammar rule just contains
1380     * individual characters on the right side of its grammar rule, then it is a
1381     * "terminal symbol" in *our* terms.
1382     *
1383     * @param rule - Bison grammar rule number
1384     */
1385    inline static bool _isRuleTerminalSymbol(int rule) {
1386        for (int i = yyprhs[rule]; yyrhs[i] != -1; ++i)
1387            if (yyrhs[i] >= YYNTOKENS) return false;
1388        return true;
1389    }
1390    
1391    /**
1392     * Returns additional informations to the given grammar @a rule.
1393     *
1394     * @param rule - grammar rule index to retrieve informations about
1395     * @param nextExpectedChars - must already be filled with the characters
1396     *                            expected to be coming next
1397     */
1398    inline static BisonSymbolInfo _symbolInfoForRule(int rule, const String& nextExpectedChars) {
1399        BisonSymbolInfo info;
1400        info.isTerminalSymbol = _isRuleTerminalSymbol(rule);
1401        if (info.isTerminalSymbol) info.nextExpectedChars  = nextExpectedChars;
1402        return info;
1403    }
1404    
1405    #endif // HAVE_BISON_MAJ >= 3
1406    
1407    /**
1408     * Returns the human readable name of the given @a token.
1409     */
1410    inline static String _tokenName(int token) {
1411        String s = yytname[token];
1412        // remove leading and trailing apostrophes that Bison usually adds to
1413        // ASCII characters used directly in grammar rules
1414        if (s.empty()) return s;
1415        if (s[0] == '\'') s.erase(0, 1);
1416        if (s.empty()) return s;
1417        if (s[s.size() - 1] == '\'') s.erase(s.size() - 1);
1418        return s;
1419    }
1420    
1421    /**
1422     * Assumes the given @a token is exactly one character and returns that
1423     * character. This must be changed in future, i.e. in case Unicode characters
1424     * will be introduced in the LSCP grammar one day.
1425     */
1426    inline static char _tokenChar(int token) {
1427        String s = _tokenName(token);
1428        if (s == "\\n") return '\n';
1429        if (s == "\\r") return '\r';
1430        return _tokenName(token)[0];
1431    }
1432    
1433    /**
1434     * Implements Bison's so called "reduce" action, according to Bison's LALR(1)
1435     * parser algorithm.
1436     */
1437    inline static int _yyReduce(std::vector<YYTYPE_INT16>& stack, const int& rule) {
1438        if (stack.empty()) throw 1; // severe error
1439        const int len = yyr2[rule];
1440        stack.resize(stack.size() - len);
1441        YYTYPE_INT16 newState = yypgoto[yyr1[rule] - YYNTOKENS] + stack.back();
1442        if (0 <= newState && newState <= YYLAST && yycheck[newState] == stack.back())
1443            newState = yytable[newState];
1444        else
1445            newState = yydefgoto[yyr1[rule] - YYNTOKENS];
1446        stack.push_back(newState);
1447        return newState;
1448    }
1449    
1450    /**
1451     * Implements Bison's so called "default reduce" action, according to Bison's
1452     * LALR(1) parser algorithm.
1453     */
1454    inline static int _yyDefaultReduce(std::vector<YYTYPE_INT16>& stack) {
1455        if (stack.empty()) throw 2; // severe error
1456        int rule = yydefact[stack.back()];
1457        if (rule <= 0 || rule >= YYNRULES) throw 3; // no rule, something is wrong
1458        return _yyReduce(stack, rule);
1459    }
1460    
1461    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    /*
1483     * YYTERROR macro was removed in Bison 3.6.0, we need it in function below.
1484     */
1485    #ifndef YYTERROR
1486    # define YYTERROR YYSYMBOL_YYerror
1487    #endif
1488    
1489    #define DEBUG_BISON_SYNTAX_ERROR_WALKER 0
1490    
1491    /**
1492     * Tries to find the next expected grammar symbols according to the given
1493     * precise parse position & state represented by @a stack, according to Bison's
1494     * LALR(1) parser algorithm.
1495     *
1496     * This function is given a Bison parser symbol stack, reflecting the parser's
1497     * entire state at a certain point, i.e. when a syntax error occured. This
1498     * function will then walk ahead the potential parse tree starting from the
1499     * current head of the given symbol stack. This function will call itself
1500     * recursively to scan the individual parse tree branches. As soon as it hits
1501     * on the next non-terminal grammar symbol in one parse tree branch, it adds the
1502     * found non-terminal symbol to @a expectedSymbols and aborts scanning the
1503     * respective tree branch further. If any local parser state is reached a second
1504     * time, the respective parse tree is aborted to avoid any endless recursion.
1505     *
1506     * @param stack - current Bison (yacc) symbol stack to be examined
1507     * @param expectedSymbols - will be filled with next expected grammar symbols
1508     * @param nextExpectedChars - just for internal purpose, due to the recursive
1509     *                            implementation of this function, do supply an
1510     *                            empty string for this argument
1511     * @param history - only for internal purpose, keeps a history of all previous
1512     *                  parser symbol stacks (just for avoiding endless recursion in
1513     *                  this recursive algorithm), do supply an empty history
1514     * @param depth - just for internal debugging purposes, do not supply it
1515     */
1516    static void walkAndFillExpectedSymbols(
1517        std::vector<YYTYPE_INT16>& stack,
1518        std::map<String,BisonSymbolInfo>& expectedSymbols,
1519        String& nextExpectedChars, YYStackHistory& history, int depth = 0)
1520    {
1521    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1522        printf("\n");
1523        for (int i = 0; i < depth; ++i) printf("\t");
1524        printf("Symbol stack:");
1525        for (int i = 0; i < stack.size(); ++i) {
1526            printf(" %d", stack[i]);
1527        }
1528        printf("\n");
1529    #endif
1530        startLabel:
1531    
1532        // detect endless recursion
1533        if (history.count(stack)) return;
1534        history.insert(stack);
1535    
1536        if (stack.empty()) {
1537    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1538            for (int i = 0; i < depth; ++i) printf("\t");
1539            printf("(EMPTY STACK)\n");
1540    #endif
1541            return;
1542        }
1543    
1544        int state = stack[stack.size() - 1];
1545        int n = yypact[state];
1546        if (n == YYPACT_NINF) { // default reduction required ...
1547            // get default reduction rule for this state
1548            n = yydefact[state];
1549            if (n <= 0 || n >= YYNRULES) {
1550    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1551                for (int i = 0; i < depth; ++i) printf("\t");
1552                printf("(EMPTY RULE)\n");
1553    #endif
1554                return; // no rule, something is wrong
1555            }
1556    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1557            for (int i = 0; i < depth; ++i) printf("\t");
1558            printf("(default reduction)\n");
1559    #endif
1560            #if HAVE_BISON_MAJ >= 3 || !defined(HAVE_BISON_MAJ)
1561            if (!nextExpectedChars.empty() || !_isRuleTerminalSymbol(n, stack)) {
1562            #else
1563            if (!nextExpectedChars.empty() || !_isRuleTerminalSymbol(n)) {
1564            #endif
1565                // Return the new resolved expected symbol (left-hand symbol of grammar
1566                // rule), then we're done in this state. (If the same symbol can be
1567                // matched on different ways, then it is non-terminal symbol.)
1568                bool ambigious =
1569                    expectedSymbols.count(yytname[yyr1[n]]) &&
1570                    expectedSymbols[yytname[yyr1[n]]].nextExpectedChars != nextExpectedChars;
1571                #if HAVE_BISON_MAJ >= 3 || !defined(HAVE_BISON_MAJ)
1572                expectedSymbols[yytname[yyr1[n]]] = _symbolInfoForRule(n, stack, nextExpectedChars);
1573                #else
1574                expectedSymbols[yytname[yyr1[n]]] = _symbolInfoForRule(n, nextExpectedChars);
1575                #endif
1576                if (ambigious)
1577                    expectedSymbols[yytname[yyr1[n]]].isTerminalSymbol = false;
1578    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1579                for (int i = 0; i < depth; ++i) printf("\t");
1580                printf("(empty expectedChars. sym = %s)\n", yytname[yyr1[n]]);
1581    #endif
1582                return;
1583            }
1584            _yyReduce(stack, n);
1585            goto startLabel;
1586        }
1587        if (!(YYPACT_NINF < n && n <= YYLAST)) {
1588    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1589            for (int i = 0; i < depth; ++i) printf("\t");
1590            printf("(invalid action B)\n");
1591    #endif
1592            return;
1593        }
1594    
1595        // Check for duplicate states, if duplicates exist return
1596        // (this check is necessary since the introduction of the yyValid() call
1597        // below, which does not care about duplicates).
1598        for (int i = 0; i < stack.size(); ++i)
1599            for (int k = i + 1; k < stack.size(); ++k)
1600                if (stack[i] == stack[k])
1601                    return;
1602    
1603    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1604        for (int i = 0; i < depth; ++i) printf("\t");
1605        printf("Expected tokens:");
1606    #endif
1607        int begin = n < 0 ? -n : 0;
1608        //int checklim = YYLAST - n + 1;
1609        int end = YYNTOKENS;//checklim < YYNTOKENS ? checklim : YYNTOKENS;
1610        int rule, action, stackSize, nextExpectedCharsLen;
1611        for (int token = begin; token < end; ++token) {
1612            if (token <= YYTERROR) continue;
1613            if (yytname[token] == String("$undefined")) continue;
1614            if (yytname[token] == String("EXT_ASCII_CHAR")) continue;
1615            //if (yycheck[n + token] != token) goto default_reduction;
1616            if (yycheck[n + token] != token) { // default reduction suggested ...
1617                // If we are here, it means the current token in the loop would not
1618                // cause a "shift", however we don't already know whether this token
1619                // is valid or not. Because there might be several reductions
1620                // involved until one can determine whether the token causes an
1621                // error or is valid. So we use this heavy check instead:
1622                std::vector<YYTYPE_INT16> stackCopy = stack; // copy required, since reduction will take place
1623                if (!yyValid(stackCopy, _tokenChar(token))) continue; // invalid token
1624    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1625                printf(" ETdr(%s)", yytname[token]);
1626    #endif
1627                // the token is valid, "stackCopy" has been reduced accordingly
1628                // and now do recurse ...
1629                nextExpectedChars += _tokenName(token);
1630                nextExpectedCharsLen = (int)nextExpectedChars.size();
1631                walkAndFillExpectedSymbols( //FIXME: could cause stack overflow (should be a loop instead), is probably fine with our current grammar though
1632                    stackCopy, expectedSymbols, nextExpectedChars, history, depth + 1
1633                );
1634                nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'
1635                continue;
1636            }
1637    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1638            printf(" ET(%s)", yytname[token]);
1639    #endif
1640    
1641            action = yytable[n + token];
1642            if (action == 0 || action == YYTABLE_NINF) {
1643    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1644                printf(" (invalid action A) "); fflush(stdout);
1645    #endif
1646                continue; // error, ignore
1647            }
1648            if (action < 0) { // reduction with rule -action required ...
1649    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1650                printf(" (reduction) "); fflush(stdout);
1651    #endif
1652                rule = -action;
1653                goto reduce;
1654            }
1655            if (action == YYFINAL) {
1656    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1657                printf(" (ACCEPT) "); fflush(stdout);
1658    #endif
1659                continue; // "accept" state, we don't care about it here
1660            }
1661    
1662            // "shift" required ...
1663    
1664            if (std::find(stack.begin(), stack.end(), action) != stack.end()) {
1665    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1666                printf(" (duplicate state %d) ", action); fflush(stdout);
1667    #endif
1668                continue; // duplicate state, ignore it to avoid endless recursions
1669            }
1670    
1671            // "shift" / push the new state on the symbol stack and call this
1672            // function recursively, and restore the stack after the recurse return
1673            stackSize = (int)stack.size();
1674            nextExpectedCharsLen = (int)nextExpectedChars.size();
1675            stack.push_back(action);
1676            nextExpectedChars += _tokenName(token);
1677            walkAndFillExpectedSymbols( //FIXME: could cause stack overflow (should be a loop instead), is probably fine with our current grammar though
1678                stack, expectedSymbols, nextExpectedChars, history, depth + 1
1679            );
1680            stack.resize(stackSize); // restore stack
1681            nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'
1682            continue;
1683    
1684        //default_reduction: // resolve default reduction for this state
1685        //    printf(" (default red.) "); fflush(stdout);
1686        //    rule = yydefact[state];
1687    
1688        reduce: // "reduce" required
1689    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1690            printf(" (reduce by %d) ", rule); fflush(stdout);
1691    #endif
1692            if (rule == 0 || rule >= YYNRULES) {
1693    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1694                printf(" (invalid rule) "); fflush(stdout);
1695    #endif
1696                continue; // invalid rule, something is wrong
1697            }
1698            // Store the left-hand symbol of the grammar rule. (If the same symbol
1699            // can be matched on different ways, then it is non-terminal symbol.)
1700            bool ambigious =
1701                expectedSymbols.count(yytname[yyr1[rule]]) &&
1702                expectedSymbols[yytname[yyr1[rule]]].nextExpectedChars != nextExpectedChars;
1703            #if HAVE_BISON_MAJ >= 3 || !defined(HAVE_BISON_MAJ)
1704            expectedSymbols[yytname[yyr1[rule]]] = _symbolInfoForRule(rule, stack, nextExpectedChars);
1705            #else
1706            expectedSymbols[yytname[yyr1[rule]]] = _symbolInfoForRule(rule, nextExpectedChars);
1707            #endif
1708            if (ambigious)
1709                expectedSymbols[yytname[yyr1[n]]].isTerminalSymbol = false;
1710    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1711            printf(" (SYM %s) ", yytname[yyr1[rule]]); fflush(stdout);
1712    #endif
1713        }
1714    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1715        printf("\n");
1716    #endif
1717    }
1718    
1719    /**
1720     * Just a convenience wrapper on top of the actual walkAndFillExpectedSymbols()
1721     * implementation above, which can be called with less parameters than the
1722     * implementing function above actually requires.
1723     */
1724    static void walkAndFillExpectedSymbols(
1725        std::vector<YYTYPE_INT16>& stack,
1726        std::map<String,BisonSymbolInfo>& expectedSymbols)
1727    {
1728        String nextExpectedChars;
1729        YYStackHistory history;
1730    
1731        walkAndFillExpectedSymbols(
1732            stack, expectedSymbols, nextExpectedChars, history
1733        );
1734    }
1735    
1736    #define DEBUG_PUSH_PARSE 0
1737    
1738    /**
1739     * Implements parsing exactly one character (given by @a ch), continueing at the
1740     * parser position reflected by @a stack. The @a stack will hold the new parser
1741     * state after this call.
1742     *
1743     * This function is implemented according to Bison's LALR(1) parser algorithm.
1744     */
1745    static bool yyPushParse(std::vector<YYTYPE_INT16>& stack, char ch) {
1746        startLabel:
1747    
1748    #if DEBUG_PUSH_PARSE
1749        //printf("\n");
1750        //for (int i = 0; i < depth; ++i) printf("\t");
1751        printf("Symbol stack:");
1752        for (int i = 0; i < stack.size(); ++i) {
1753            printf(" %d", stack[i]);
1754        }
1755        printf(" char='%c'(%d)\n", ch, (int)ch);
1756    #endif
1757    
1758        if (stack.empty()) return false;
1759    
1760        int state = stack.back();
1761        int n = yypact[state];
1762        if (n == YYPACT_NINF) { // default reduction required ...
1763    #if DEBUG_PUSH_PARSE
1764            printf("(def reduce 1)\n");
1765    #endif
1766            state = _yyDefaultReduce(stack);
1767            goto startLabel;
1768        }
1769        if (!(YYPACT_NINF < n && n <= YYLAST)) return false;
1770    
1771        YYTYPE_INT16 token = (ch == YYEOF) ? YYEOF : yytranslate[ch];
1772        n += token;
1773        if (n < 0 || YYLAST < n || yycheck[n] != token) {
1774    #if DEBUG_PUSH_PARSE
1775            printf("(def reduce 2) n=%d token=%d\n", n, token);
1776    #endif
1777            state = _yyDefaultReduce(stack);
1778            goto startLabel;
1779        }
1780        int action = yytable[n]; // yytable[yypact[state] + token]
1781        if (action == 0 || action == YYTABLE_NINF) throw 4;
1782        if (action < 0) {
1783    #if DEBUG_PUSH_PARSE
1784            printf("(reduce)\n");
1785    #endif
1786            int rule = -action;
1787            state = _yyReduce(stack, rule);
1788            goto startLabel;
1789        }
1790        if (action == YYFINAL) return true; // final state reached
1791    
1792    #if DEBUG_PUSH_PARSE
1793        printf("(push)\n");
1794    #endif
1795        // push new state
1796        state = action;
1797        stack.push_back(state);
1798        return true;
1799    }
1800    
1801    /**
1802     * Returns true if parsing ahead with given character @a ch is syntactically
1803     * valid according to the LSCP grammar, it returns false if it would create a
1804     * parse error.
1805     *
1806     * The @a stack will reflect the new parser state after this call.
1807     *
1808     * This is just a wrapper ontop of yyPushParse() which converts parser
1809     * exceptions thrown by yyPushParse() into @c false return value.
1810     */
1811    static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch) {
1812        try {
1813            return yyPushParse(stack, ch);
1814        } catch (int i) {
1815    #if DEBUG_PUSH_PARSE
1816            printf("exception %d\n", i);
1817    #endif
1818            return false;
1819        } catch (...) {
1820            return false;
1821        }
1822    }
1823    
1824    /**
1825     * Returns the amount of correct characters of given @a line from the left,
1826     * according to the LSCP grammar.
1827     *
1828     * @param stack - a Bison symbol stack to work with
1829     * @param line  - the input line to check
1830     * @param bAutoCorrect - if true: try to correct obvious, trivial syntax errors
1831     */
1832    static int yyValidCharacters(std::vector<YYTYPE_INT16>& stack, String& line, bool bAutoCorrect) {
1833        int i;
1834        for (i = 0; i < line.size(); ++i) {
1835            // since we might check the same parser state twice against the current
1836            // char here below, and since the symbol stack might be altered
1837            // (i.e. shifted or reduced) on syntax errors, we have to backup the
1838            // current symbol stack and restore it on syntax errors below
1839            std::vector<YYTYPE_INT16> stackCopy = stack;
1840            if (yyValid(stackCopy, line[i])) {
1841                stack = stackCopy;
1842                continue;
1843            }
1844            if (bAutoCorrect) {
1845                // try trivial corrections, i.e. upper case character instead of
1846                // lower case, subline instead of space and vice versa
1847                char c;
1848                if      (line[i] == ' ') c = '_';
1849                else if (line[i] == '_') c = ' ';
1850                else if (isLowerCaseAlphaChar(line[i]))
1851                    c = alphaCharToUpperCase(line[i]);
1852                else return i;
1853                if (yyValid(stack, c)) {
1854                    line[i] = c;
1855                    continue;
1856                }
1857            }
1858            return i;
1859        }
1860        return i;
1861    }
1862    
1863    /**
1864     * Should only be called on syntax errors: returns a set of non-terminal
1865     * symbols expected to appear now/next, just at the point where the syntax
1866     * error appeared.
1867     *
1868     * @returns names of the non-terminal symbols expected at this parse position
1869     */
1870    static std::set<String> yyExpectedSymbols() {
1871        std::map<String,BisonSymbolInfo> expectedSymbols;
1872        yyparse_param_t* param = GetCurrentYaccSession();
1873        YYTYPE_INT16* ss = (*param->ppStackBottom);
1874        YYTYPE_INT16* sp = (*param->ppStackTop);
1875        int iStackSize   = int(sp - ss + 1);
1876        // copy and wrap parser's symbol stack into a convenient STL container
1877        std::vector<YYTYPE_INT16> stack;
1878        for (int i = 0; i < iStackSize; ++i) {
1879            stack.push_back(ss[i]);
1880        }
1881        // do the actual parser work
1882        walkAndFillExpectedSymbols(stack, expectedSymbols);
1883    
1884        // convert expectedSymbols to the result set
1885        std::set<String> result;
1886        for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1887             it != expectedSymbols.end(); ++it) result.insert(it->first);
1888        return result;
1889    }
1890    
1891    #define DEBUG_YY_AUTO_COMPLETE 0
1892    
1893    /**
1894     * Generates and returns an auto completion string for the current parser
1895     * state given by @a stack. That means, this function will return the longest
1896     * sequence of characters that is uniqueley expected to be sent next by the LSCP
1897     * client. Or in other words, if the LSCP client would send any other
1898     * character(s) than returned here, it would result in a syntax error.
1899     *
1900     * This function takes a Bison symbol @a stack as argument, reflecting the
1901     * current Bison parser state, and evaluates the individual grammar tree
1902     * branches starting from that particular position. It walks along the grammar
1903     * tree as long as there is only one possible tree branch and assembles a string
1904     * of input characters that would lead to that walk through the grammar tree. As
1905     * soon as a position in the grammar tree is reached where there are multiple
1906     * possible tree branches, this algorithm will stop, since the user could have
1907     * multiple possible valid characters he could type at that point, thus auto
1908     * completion would no longer be unique at that point.
1909     *
1910     * Regarding @a history argument: read the description on YYStackHistory for the
1911     * purpose behind this argument.
1912     *
1913     * @param stack - current Bison (yacc) symbol stack to create auto completion for
1914     * @param history - only for internal purpose, keeps a history of all previous
1915     *                  parser symbol stacks (just for avoiding endless recursion in
1916     *                  this auto completion algorithm), do supply an empty history
1917     * @param depth - just for internal debugging purposes, do not supply anything
1918     * @returns auto completion for current, given parser state
1919     */
1920    static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack, YYStackHistory& history, int depth = 0) {
1921        std::map<String,BisonSymbolInfo> expectedSymbols;
1922        walkAndFillExpectedSymbols(stack, expectedSymbols);
1923        if (expectedSymbols.size() == 1) {
1924            String name          = expectedSymbols.begin()->first;
1925            BisonSymbolInfo info = expectedSymbols.begin()->second;
1926    #if DEBUG_YY_AUTO_COMPLETE
1927            for (int q = 0; q < depth; ++q) printf("  ");
1928            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());
1929    #endif
1930            if (info.nextExpectedChars.empty() || !info.isTerminalSymbol) return "";
1931            // parse forward with the suggested auto completion
1932            std::vector<YYTYPE_INT16> stackCopy = stack;
1933            yyValidCharacters(stackCopy, info.nextExpectedChars, false);
1934            // detect endless recursion
1935            if (history.count(stackCopy)) return "";
1936            history.insert(stackCopy);
1937            // recurse and return the expanded auto completion with maximum length
1938            return info.nextExpectedChars + yyAutoComplete(stackCopy, history, depth + 1);
1939        } else if (expectedSymbols.size() == 0) {
1940    #if DEBUG_YY_AUTO_COMPLETE
1941            for (int q = 0; q < depth; ++q) printf("  ");
1942            printf("(%d) No sub suggestion.\n", depth);
1943    #endif
1944            return "";
1945        } else if (expectedSymbols.size() > 1) {
1946    #if DEBUG_YY_AUTO_COMPLETE
1947            for (int q = 0; q < depth; ++q) printf("  ");
1948            printf("(%d) Multiple sub possibilities (before expansion):", depth);
1949            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1950                 it != expectedSymbols.end(); ++it)
1951            {
1952                printf(" %s (..%s)", it->first.c_str(), it->second.nextExpectedChars.c_str());
1953            }
1954            printf("\n");
1955    #endif
1956            // check if any of the possibilites is a non-terminal symbol, if so, we
1957            // have no way for auto completion at this point
1958            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1959                 it != expectedSymbols.end(); ++it)
1960            {
1961                if (!it->second.isTerminalSymbol) {
1962    #if DEBUG_YY_AUTO_COMPLETE
1963                    for (int q = 0; q < depth; ++q) printf("  ");
1964                    printf("(%d) Non-terminal exists. Stop.", depth);
1965    #endif
1966                    return "";
1967                }
1968            }
1969    #if 0 // commented out for now, since practically irrelevant and VERY slow ...
1970            // all possibilities are terminal symbols, so expand all possiblities to
1971            // maximum length with a recursive call for each possibility
1972            for (std::map<String,BisonSymbolInfo>::iterator it = expectedSymbols.begin();
1973                 it != expectedSymbols.end(); ++it)
1974            {
1975                if (it->second.nextExpectedChars.empty() || !it->second.isTerminalSymbol) continue;
1976                // parse forward with this particular suggested auto completion
1977                std::vector<YYTYPE_INT16> stackCopy = stack;
1978                yyValidCharacters(stackCopy, it->second.nextExpectedChars, false);
1979                // detect endless recursion
1980                if (history.count(stackCopy)) continue;
1981                history.insert(stackCopy);
1982                // recurse and return the total possible auto completion for this
1983                // grammar tree branch
1984                it->second.nextExpectedChars += yyAutoComplete(stackCopy, history, depth + 1);
1985            }
1986    #endif
1987            // try to find the longest common string all possibilities start with
1988            // (from the left)
1989            String sCommon;
1990            for (int i = 0; true; ++i) {
1991                char c = '\0';
1992                for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1993                     it != expectedSymbols.end(); ++it)
1994                {
1995                    if (i >= it->second.nextExpectedChars.size())
1996                        goto commonSearchEndLabel;
1997                    if (it == expectedSymbols.begin())
1998                        c = it->second.nextExpectedChars[i];
1999                    if (c != it->second.nextExpectedChars[i])
2000                        goto commonSearchEndLabel;
2001                    if (it == --expectedSymbols.end())
2002                        sCommon += c;
2003                }
2004            }
2005            commonSearchEndLabel:
2006    #if DEBUG_YY_AUTO_COMPLETE
2007            for (int q = 0; q < depth; ++q) printf("  ");
2008            printf("(%d) Multiple sub possibilities (after expansion):", depth);
2009            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
2010                 it != expectedSymbols.end(); ++it)
2011            {
2012                printf(" %s (..%s)", it->first.c_str(), it->second.nextExpectedChars.c_str());
2013            }
2014            printf("\n");
2015            for (int q = 0; q < depth; ++q) printf("  ");
2016            printf("(%d) Common sub possibility: '%s'\n", depth, sCommon.c_str());
2017    #endif
2018            return sCommon;
2019        }
2020        return ""; // just pro forma, should never happen though
2021    }
2022    
2023    /**
2024     * Just a convenience wrapper on top of the actual yyAutoComplete()
2025     * implementation. See its description above for details.
2026     */
2027    static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack) {
2028        YYStackHistory history;
2029        return yyAutoComplete(stack, history);
2030    }
2031    
2032    namespace LinuxSampler {
2033    
2034    #define DEBUG_SHELL_INTERACTION 0
2035    
2036    /**
2037     * If LSCP shell mode is enabled for the respective LSCP client connection, then
2038     * this function is called on every new byte received from that client. It will
2039     * check the current total input line and reply to the LSCP shell with a
2040     * specially crafted string, which allows the shell to provide colored syntax
2041     * highlighting and potential auto completion in the shell.
2042     *
2043     * It also performs auto correction of obvious & trivial syntax mistakes if
2044     * requested.
2045     *
2046     * The return value of this function will be sent to the client. It contains one
2047     * line specially formatted for the LSCP shell application, which can easily be
2048     * processed by the client/shell for extracting its necessary informations like
2049     * which part of the current command line is syntactically correct, which part
2050     * is incorrect, what could be auto completed right now, etc. So all the heavy
2051     * grammar evaluation tasks are peformed by the LSCP server for the LSCP shell
2052     * application (which is desgined as a thin client), so the LSCP shell
2053     * application will only have to show the results of the LSCP server's
2054     * evaluation to the user on the screen.
2055     *
2056     * @param line - the current command line to be evaluated by LSCP parser
2057     * @param param = reentrant parser session parameters
2058     * @param possibilities - whether all possibilities shall be shown
2059     * @returns LSCP shell response line to be returned to the client
2060     */
2061    String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param, bool possibilities) {
2062        // first, determine how many characters (starting from the left) of the
2063        // given input line are already syntactically correct
2064        std::vector<YYTYPE_INT16> stack;
2065        stack.push_back(0); // every Bison symbol stack starts with state zero
2066        String l = line + '\n'; // '\n' to pretend ENTER as if the line was now complete
2067        int n = yyValidCharacters(stack, l, param->bShellAutoCorrect);
2068    
2069        // if auto correction is enabled, apply the auto corrected string to
2070        // intput/output string 'line'
2071        if (param->bShellAutoCorrect) {
2072            int nMin = int( (n < line.length()) ? n : line.length() );
2073            line.replace(0, nMin, l.substr(0, nMin));
2074        }
2075    
2076        ssize_t cursorPos = line.size() + param->iCursorOffset;
2077        if (cursorPos < 0) cursorPos = 0;
2078    
2079        // generate an info string that will be sent to the LSCP shell for letting
2080        // it know which part is correct, which one is wrong, where is the cursor, etc.
2081        String result = line;
2082        result.insert(n <= result.length() ? n : result.length(), LSCP_SHK_GOOD_FRONT);
2083        result.insert(cursorPos <= n ? cursorPos : cursorPos + String(LSCP_SHK_GOOD_FRONT).length(), LSCP_SHK_CURSOR);
2084        int code = (n > line.length()) ? LSCP_SHU_COMPLETE : (n < line.length()) ?
2085                   LSCP_SHU_SYNTAX_ERR : LSCP_SHU_INCOMPLETE;
2086        result = "SHU:" + ToString(code) + ":" + result;
2087        //if (n > line.length()) result += " [OK]";
2088    
2089        // get a clean parser stack to the last valid parse position
2090        // (due to the appended '\n' character above, and on syntax errors, the
2091        // symbol stack might be in undesired, i.e. reduced state)
2092        stack.clear();
2093        stack.push_back(0); // every Bison symbol stack starts with state zero
2094        l = line.substr(0, n);
2095        if (!l.empty()) yyValidCharacters(stack, l, param->bShellAutoCorrect);
2096    
2097        // generate auto completion suggestion (based on the current parser stack)
2098        std::vector<YYTYPE_INT16> stackCopy = stack; // make a copy, since yyAutoComplete() might alter the stack
2099        String sSuggestion = yyAutoComplete(stackCopy);
2100        if (!sSuggestion.empty()) result += LSCP_SHK_SUGGEST_BACK + sSuggestion;
2101    
2102        if (possibilities) {
2103            // append all possible terminals and non-terminals according to
2104            // current parser state
2105            std::map<String,BisonSymbolInfo> expectedSymbols;
2106            walkAndFillExpectedSymbols(stack, expectedSymbols);
2107    
2108            // pretend to LSCP shell that the following terminal symbols were
2109            // non-terminal symbols (since they are not human visible for auto
2110            // completion on the shell's screen)
2111            std::set<String> specialNonTerminals;
2112            specialNonTerminals.insert("SP");
2113            specialNonTerminals.insert("CR");
2114            specialNonTerminals.insert("LF");
2115    
2116            String sPossibilities;
2117            int iNonTerminals = 0;
2118            int iTerminals    = 0;
2119            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
2120                 it != expectedSymbols.end(); ++it)
2121            {
2122                if (!sPossibilities.empty()) sPossibilities += " | ";
2123                if (it->second.isTerminalSymbol && !specialNonTerminals.count(it->first)) {
2124                    sPossibilities += it->first;
2125                    iTerminals++;
2126                } else {
2127                    sPossibilities += "<" + it->first + ">";
2128                    iNonTerminals++;
2129                }
2130            }
2131            if (!sPossibilities.empty() && (iNonTerminals || iTerminals > 1)) {
2132                result += LSCP_SHK_POSSIBILITIES_BACK + sPossibilities;
2133            }
2134        }
2135    
2136    #if DEBUG_SHELL_INTERACTION
2137        printf("%s\n", result.c_str());
2138    #endif
2139    
2140        return result;
2141    }
2142    
2143    /**
2144     * Clears input buffer.
2145   */   */
2146  void restart(yyparse_param_t* pparam, int& yychar) {  void restart(yyparse_param_t* pparam, int& yychar) {
2147      // restart scanner      bytes = 0;
2148      yyrestart(stdin, pparam->pScanner);      ptr   = 0;
2149      // reset lookahead symbol      sLastError = "";
2150      yyclearin;      sParsed = "";
2151    }
2152    
2153  }  }

Legend:
Removed from v.185  
changed lines
  Added in v.4002

  ViewVC Help
Powered by ViewVC