/[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 4002 - (show annotations) (download)
Mon Nov 22 20:06:26 2021 UTC (2 years, 4 months ago) by schoenebeck
File size: 114236 byte(s)
* Fix compiler error with release tarball if no Bison installed
  (SVN version still requires Flex and Bison being installed).

* Bumped version (2.2.0.svn7).

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

  ViewVC Help
Powered by ViewVC