/[svn]/linuxsampler/trunk/src/network/lscp.y
ViewVC logotype

Contents of /linuxsampler/trunk/src/network/lscp.y

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2532 - (show annotations) (download)
Wed Mar 5 17:29:15 2014 UTC (10 years, 1 month ago) by schoenebeck
File size: 113552 byte(s)
* LSCP server: fixed crash caused by endless recursion in
  LSCP shell grammar evaluation algorithm.
* LSCP shell: quit shell app when TCP connection aborted.
* Bumped version (1.0.0.svn36).

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2014 Christian Schoenebeck *
7 * *
8 * 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 *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 /*
25 The parser's C++ source files should be automatically (re)generated if
26 this file was modified. If not, or in case you want explicitly
27 regenerate the parser C++ files, run 'make parser'. In both cases you
28 need to have bison or another yacc compatible parser generator
29 installed though.
30 */
31
32 %{
33
34 #include "lscpparser.h"
35 #include "lscpserver.h"
36 #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
44 #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
49 void restart(yyparse_param_t* pparam, int& yychar);
50 #define RESTART restart((yyparse_param_t*) YYPARSE_PARAM, yychar)
51
52 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
54 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
59 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
81 // (bison expects it to return the numerical ID of the next
82 // "recognized token" from the input stream)
83 int yylex(YYSTYPE* yylval) {
84 // check if we have to read new characters
85 if (ptr >= bytes) {
86 bytes = GetLSCPCommand(buf, 1023);
87 ptr = 0;
88 if (bytes < 0) {
89 bytes = 0;
90 return 0;
91 }
92 }
93 // 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
178 %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 // tell bison to spit out verbose syntax error messages
192 %error-verbose
193
194 %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
201 %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
207
208 %%
209
210 //TODO: return more meaningful error messages
211
212 /*
213 The LSCP specification document input file (Documentation/lscp.xml) is
214 automatically updated with this file using the scripts/update_grammar.pl
215 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 !!!
220
221 input : line { INCREMENT_LINE; if (!$1.empty()) LSCPSERVER->AnswerClient($1); return LSCP_DONE; }
222 | 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 statement : /* epsilon (empty statement/line ignored) */ { $$ = ""; }
230 | comment { $$ = ""; }
231 | command
232 ;
233
234 comment : '#'
235 | comment '#'
236 | comment SP
237 | comment number
238 | comment string
239 ;
240
241 command : ADD SP add_instruction { $$ = $3; }
242 | MAP SP map_instruction { $$ = $3; }
243 | UNMAP SP unmap_instruction { $$ = $3; }
244 | GET SP get_instruction { $$ = $3; }
245 | CREATE SP create_instruction { $$ = $3; }
246 | DESTROY SP destroy_instruction { $$ = $3; }
247 | LIST SP list_instruction { $$ = $3; }
248 | LOAD SP load_instruction { $$ = $3; }
249 | REMOVE SP remove_instruction { $$ = $3; }
250 | SET SP set_instruction { $$ = $3; }
251 | SUBSCRIBE SP subscribe_event { $$ = $3; }
252 | UNSUBSCRIBE SP unsubscribe_event { $$ = $3; }
253 | RESET SP reset_instruction { $$ = $3; }
254 | 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(); }
264 | QUIT { LSCPSERVER->AnswerClient("Bye!\r\n"); return LSCP_QUIT; }
265 ;
266
267 add_instruction : CHANNEL { $$ = LSCPSERVER->AddChannel(); }
268 | CHANNEL SP MIDI_INPUT SP sampler_channel SP device_index { $$ = LSCPSERVER->AddChannelMidiInput($5,$7); }
269 | CHANNEL SP MIDI_INPUT SP sampler_channel SP device_index SP midi_input_port_index { $$ = LSCPSERVER->AddChannelMidiInput($5,$7,$9); }
270 | DB_INSTRUMENT_DIRECTORY SP db_path { $$ = LSCPSERVER->AddDbInstrumentDirectory($3); }
271 | DB_INSTRUMENTS SP NON_MODAL SP scan_mode SP db_path SP filename { $$ = LSCPSERVER->AddDbInstruments($5,$7,$9, true); }
272 | 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 | 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 | DB_INSTRUMENTS SP NON_MODAL SP db_path SP filename SP instrument_index { $$ = LSCPSERVER->AddDbInstruments($5,$7,$9, true); }
277 | DB_INSTRUMENTS SP db_path SP filename { $$ = LSCPSERVER->AddDbInstruments($3,$5); }
278 | DB_INSTRUMENTS SP db_path SP filename SP instrument_index { $$ = LSCPSERVER->AddDbInstruments($3,$5,$7); }
279 | MIDI_INSTRUMENT_MAP { $$ = LSCPSERVER->AddMidiInstrumentMap(); }
280 | MIDI_INSTRUMENT_MAP SP map_name { $$ = LSCPSERVER->AddMidiInstrumentMap($3); }
281 | SEND_EFFECT_CHAIN SP device_index { $$ = LSCPSERVER->AddSendEffectChain($3); }
282 ;
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(); }
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(); }
380 | 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); }
382 | MIDI_INPUT_DRIVER_PARAMETER SP INFO SP string SP string SP key_val_list { $$ = LSCPSERVER->GetMidiInputDriverParameterInfo($5, $7, $9); }
383 | AVAILABLE_AUDIO_OUTPUT_DRIVERS { $$ = LSCPSERVER->GetAvailableAudioOutputDrivers(); }
384 | AUDIO_OUTPUT_DRIVER SP INFO SP string { $$ = LSCPSERVER->GetAudioOutputDriverInfo($5); }
385 | AUDIO_OUTPUT_DRIVER_PARAMETER SP INFO SP string SP string { $$ = LSCPSERVER->GetAudioOutputDriverParameterInfo($5, $7); }
386 | AUDIO_OUTPUT_DRIVER_PARAMETER SP INFO SP string SP string SP key_val_list { $$ = LSCPSERVER->GetAudioOutputDriverParameterInfo($5, $7, $9); }
387 | AUDIO_OUTPUT_DEVICES { $$ = LSCPSERVER->GetAudioOutputDeviceCount(); }
388 | MIDI_INPUT_DEVICES { $$ = LSCPSERVER->GetMidiInputDeviceCount(); }
389 | AUDIO_OUTPUT_DEVICE SP INFO SP number { $$ = LSCPSERVER->GetAudioOutputDeviceInfo($5); }
390 | MIDI_INPUT_DEVICE SP INFO SP number { $$ = LSCPSERVER->GetMidiInputDeviceInfo($5); }
391 | MIDI_INPUT_PORT SP INFO SP number SP number { $$ = LSCPSERVER->GetMidiInputPortInfo($5, $7); }
392 | MIDI_INPUT_PORT_PARAMETER SP INFO SP number SP number SP string { $$ = LSCPSERVER->GetMidiInputPortParameterInfo($5, $7, $9); }
393 | AUDIO_OUTPUT_CHANNEL SP INFO SP number SP number { $$ = LSCPSERVER->GetAudioOutputChannelInfo($5, $7); }
394 | AUDIO_OUTPUT_CHANNEL_PARAMETER SP INFO SP number SP number SP string { $$ = LSCPSERVER->GetAudioOutputChannelParameterInfo($5, $7, $9); }
395 | CHANNELS { $$ = LSCPSERVER->GetChannels(); }
396 | CHANNEL SP INFO SP sampler_channel { $$ = LSCPSERVER->GetChannelInfo($5); }
397 | CHANNEL SP BUFFER_FILL SP buffer_size_type SP sampler_channel { $$ = LSCPSERVER->GetBufferFill($5, $7); }
398 | CHANNEL SP STREAM_COUNT SP sampler_channel { $$ = LSCPSERVER->GetStreamCount($5); }
399 | CHANNEL SP VOICE_COUNT SP sampler_channel { $$ = LSCPSERVER->GetVoiceCount($5); }
400 | ENGINE SP INFO SP engine_name { $$ = LSCPSERVER->GetEngineInfo($5); }
401 | SERVER SP INFO { $$ = LSCPSERVER->GetServerInfo(); }
402 | TOTAL_STREAM_COUNT { $$ = LSCPSERVER->GetTotalStreamCount(); }
403 | TOTAL_VOICE_COUNT { $$ = LSCPSERVER->GetTotalVoiceCount(); }
404 | 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); }
427 | 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); }
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); }
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; }
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); }
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); }
453 | AUDIO_OUTPUT_DEVICE SP string { $$ = LSCPSERVER->CreateAudioOutputDevice($3); }
454 | MIDI_INPUT_DEVICE SP string SP key_val_list { $$ = LSCPSERVER->CreateMidiInputDevice($3,$5); }
455 | 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); }
485 | 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; }
491 | 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); }
501 | 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); }
503 | MIDI_INPUT SP sampler_channel SP device_index SP midi_input_port_index SP midi_input_channel_index { $$ = LSCPSERVER->SetMIDIInput($5, $7, $9, $3); }
504 | MIDI_INPUT_DEVICE SP sampler_channel SP device_index { $$ = LSCPSERVER->SetMIDIInputDevice($5, $3); }
505 | MIDI_INPUT_PORT SP sampler_channel SP midi_input_port_index { $$ = LSCPSERVER->SetMIDIInputPort($5, $3); }
506 | MIDI_INPUT_CHANNEL SP sampler_channel SP midi_input_channel_index { $$ = LSCPSERVER->SetMIDIInputChannel($5, $3); }
507 | MIDI_INPUT_TYPE SP sampler_channel SP midi_input_type_name { $$ = LSCPSERVER->SetMIDIInputType($5, $3); }
508 | VOLUME SP sampler_channel SP volume_value { $$ = LSCPSERVER->SetVolume($5, $3); }
509 | MUTE SP sampler_channel SP boolean { $$ = LSCPSERVER->SetChannelMute($5, $3); }
510 | 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; }
527 | key_val_list SP string '=' param_val_list { $$ = $1; $$[$3] = $5; }
528 ;
529
530 buffer_size_type : BYTES { $$ = fill_response_bytes; }
531 | PERCENTAGE { $$ = fill_response_percentage; }
532 ;
533
534 list_instruction : AUDIO_OUTPUT_DEVICES { $$ = LSCPSERVER->GetAudioOutputDevices(); }
535 | MIDI_INPUT_DEVICES { $$ = LSCPSERVER->GetMidiInputDevices(); }
536 | CHANNELS { $$ = LSCPSERVER->ListChannels(); }
537 | CHANNEL SP MIDI_INPUTS SP sampler_channel { $$ = LSCPSERVER->ListChannelMidiInputs($5); }
538 | AVAILABLE_ENGINES { $$ = LSCPSERVER->ListAvailableEngines(); }
539 | 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); }
559 | NON_MODAL SP filename SP instrument_index SP sampler_channel { $$ = LSCPSERVER->LoadInstrument($3, $5, $7, true); }
560 ;
561
562 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
574 ;
575
576 audio_channel_index : number
577 ;
578
579 audio_output_type_name : string
580 ;
581
582 midi_input_port_index : number
583 ;
584
585 midi_input_channel_index : number
586 | ALL { $$ = 16; }
587 ;
588
589 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
605 | number { $$ = $1; }
606 ;
607
608 control_value : real
609 ;
610
611 sampler_channel : number
612 ;
613
614 instrument_index : number
615 ;
616
617 fx_send_id : number
618 ;
619
620 engine_name : string
621 ;
622
623 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
661 | param_val_list','param_val { $$ = $1 + "," + $3; }
662 ;
663
664 //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 param_val : string { $$ = "\'" + $1 + "\'"; }
666 | stringval { $$ = "\'" + $1 + "\'"; }
667 | number { std::stringstream ss; ss << "\'" << $1 << "\'"; $$ = ss.str(); }
668 | 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 !!!
691
692
693 // atomic variable symbol rules
694
695 boolean : number { $$ = $1; }
696 | string { $$ = -1; }
697 ;
698
699 dotnum : digits '.' digits { std::stringstream ss($1 + "." + $3); ss.imbue(std::locale::classic()); ss >> $$; }
700 | '+' 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 real : digits '.' digits { std::stringstream ss($1 + "." + $3); ss.imbue(std::locale::classic()); ss >> $$; }
705 | '+' digits '.' digits { std::stringstream ss($2 + "." + $4); ss.imbue(std::locale::classic()); ss >> $$; }
706 | '-' 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
713 digits : digit { $$ = $1; }
714 | digits digit { $$ = $1 + $2; }
715 ;
716
717 digit : '0' { $$ = '0'; }
718 | '1' { $$ = '1'; }
719 | '2' { $$ = '2'; }
720 | '3' { $$ = '3'; }
721 | '4' { $$ = '4'; }
722 | '5' { $$ = '5'; }
723 | '6' { $$ = '6'; }
724 | '7' { $$ = '7'; }
725 | '8' { $$ = '8'; }
726 | '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()); }
764 | '1' digits { $$ = atoi(String(String("1") + $2).c_str()); }
765 | '2' digits { $$ = atoi(String(String("2") + $2).c_str()); }
766 | '3' digits { $$ = atoi(String(String("3") + $2).c_str()); }
767 | '4' digits { $$ = atoi(String(String("4") + $2).c_str()); }
768 | '5' digits { $$ = atoi(String(String("5") + $2).c_str()); }
769 | '6' digits { $$ = atoi(String(String("6") + $2).c_str()); }
770 | '7' digits { $$ = atoi(String(String("7") + $2).c_str()); }
771 | '8' digits { $$ = atoi(String(String("8") + $2).c_str()); }
772 | '9' digits { $$ = atoi(String(String("9") + $2).c_str()); }
773 ;
774
775 path : '\'' path_base '\'' { $$ = $2; }
776 | '\"' path_base '\"' { $$ = $2; }
777 ;
778
779 path_base : path_prefix path_body { $$ = $1 + $2; }
780 ;
781
782 path_prefix : '/' { $$ = Path(); }
783 | alpha_char ':' '/' { Path p; p.setDrive($1); $$ = p; }
784 ;
785
786 path_body : /* epsilon (empty argument) */ { $$ = Path(); }
787 | path_body '/' { $$ = $1; }
788 | path_body text_escaped_base { Path p; p.appendNode($2); $$ = $1 + p; }
789 ;
790
791 stringval : '\'' text '\'' { $$ = $2; }
792 | '\"' text '\"' { $$ = $2; }
793 ;
794
795 stringval_escaped : '\'' text_escaped '\'' { $$ = $2; }
796 | '\"' text_escaped '\"' { $$ = $2; }
797 ;
798
799 text : SP { $$ = " "; }
800 | string
801 | text SP { $$ = $1 + " "; }
802 | text string { $$ = $1 + $2; }
803 ;
804
805 // like text_escaped, but missing the slash ('/') character
806 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
872
873 SP : ' '
874 ;
875
876 LF : '\n'
877 ;
878
879 CR : '\r'
880 ;
881
882 ADD : 'A''D''D'
883 ;
884
885 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'
910 ;
911
912 DESTROY : 'D''E''S''T''R''O''Y'
913 ;
914
915 LIST : 'L''I''S''T'
916 ;
917
918 LOAD : 'L''O''A''D'
919 ;
920
921 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'
931 ;
932
933 REMOVE : 'R''E''M''O''V''E'
934 ;
935
936 SET : 'S''E''T'
937 ;
938
939 SHELL : 'S''H''E''L''L'
940 ;
941
942 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 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'
961 ;
962
963 AVAILABLE_ENGINES : 'A''V''A''I''L''A''B''L''E''_''E''N''G''I''N''E''S'
964 ;
965
966 AVAILABLE_AUDIO_OUTPUT_DRIVERS : 'A''V''A''I''L''A''B''L''E''_''A''U''D''I''O''_''O''U''T''P''U''T''_''D''R''I''V''E''R''S'
967 ;
968
969 CHANNELS : 'C''H''A''N''N''E''L''S'
970 ;
971
972 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'
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'
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'
1036 ;
1037
1038 STREAM_COUNT : 'S''T''R''E''A''M''_''C''O''U''N''T'
1039 ;
1040
1041 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'
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'
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'
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'
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'
1087 ;
1088
1089 AUDIO_OUTPUT_DEVICES : 'A''U''D''I''O''_''O''U''T''P''U''T''_''D''E''V''I''C''E''S'
1090 ;
1091
1092 AUDIO_OUTPUT_DEVICE : 'A''U''D''I''O''_''O''U''T''P''U''T''_''D''E''V''I''C''E'
1093 ;
1094
1095 AUDIO_OUTPUT_DRIVER_PARAMETER : 'A''U''D''I''O''_''O''U''T''P''U''T''_''D''R''I''V''E''R''_''P''A''R''A''M''E''T''E''R'
1096 ;
1097
1098 AUDIO_OUTPUT_DRIVER : 'A''U''D''I''O''_''O''U''T''P''U''T''_''D''R''I''V''E''R'
1099 ;
1100
1101 AUDIO_OUTPUT_CHANNEL_PARAMETER : 'A''U''D''I''O''_''O''U''T''P''U''T''_''C''H''A''N''N''E''L''_''P''A''R''A''M''E''T''E''R'
1102 ;
1103
1104 AUDIO_OUTPUT_CHANNEL : 'A''U''D''I''O''_''O''U''T''P''U''T''_''C''H''A''N''N''E''L'
1105 ;
1106
1107 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'
1132 ;
1133
1134 MIDI_INPUT_DEVICE_PARAMETER : 'M''I''D''I''_''I''N''P''U''T''_''D''E''V''I''C''E''_''P''A''R''A''M''E''T''E''R'
1135 ;
1136
1137 MIDI_INPUT_PORT_PARAMETER : 'M''I''D''I''_''I''N''P''U''T''_''P''O''R''T''_''P''A''R''A''M''E''T''E''R'
1138 ;
1139
1140 MIDI_INPUT_DEVICES : 'M''I''D''I''_''I''N''P''U''T''_''D''E''V''I''C''E''S'
1141 ;
1142
1143 MIDI_INPUT_DEVICE : 'M''I''D''I''_''I''N''P''U''T''_''D''E''V''I''C''E'
1144 ;
1145
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'
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'
1162 ;
1163
1164 MIDI_INPUT_PORT : 'M''I''D''I''_''I''N''P''U''T''_''P''O''R''T'
1165 ;
1166
1167 MIDI_INPUT_CHANNEL : 'M''I''D''I''_''I''N''P''U''T''_''C''H''A''N''N''E''L'
1168 ;
1169
1170 MIDI_INPUT_TYPE : 'M''I''D''I''_''I''N''P''U''T''_''T''Y''P''E'
1171 ;
1172
1173 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'
1231 ;
1232
1233 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'
1243 ;
1244
1245 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'
1255 ;
1256
1257 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'
1273 ;
1274
1275 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'
1282 ;
1283
1284 QUIT : 'Q''U''I''T'
1285 ;
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 * 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 inline static bool _isRuleTerminalSymbol(int rule, const std::vector<YYTYPE_INT16>& stack) {
1326 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 /**
2128 * Clears input buffer.
2129 */
2130 void restart(yyparse_param_t* pparam, int& yychar) {
2131 bytes = 0;
2132 ptr = 0;
2133 sLastError = "";
2134 sParsed = "";
2135 }
2136
2137 }

  ViewVC Help
Powered by ViewVC