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

Legend:
Removed from v.826  
changed lines
  Added in v.2532

  ViewVC Help
Powered by ViewVC