/[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 3052 - (show annotations) (download)
Wed Dec 14 17:34:54 2016 UTC (7 years, 4 months ago) by schoenebeck
File size: 113946 byte(s)
- Preparations for Xcode project update.

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2014 Christian Schoenebeck *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 /*
25 The parser's C++ source files should be automatically (re)generated if
26 this file was modified. If not, or in case you want explicitly
27 regenerate the parser C++ files, run 'make parser'. In both cases you
28 need to have bison or another yacc compatible parser generator
29 installed though.
30 */
31
32 %{
33
34 #include "lscpparser.h"
35 #include "lscpserver.h"
36 #include "lscpevent.h"
37
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 // 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 #define DEBUG_BISON_SYNTAX_ERROR_WALKER 0
1483
1484 /**
1485 * Tries to find the next expected grammar symbols according to the given
1486 * precise parse position & state represented by @a stack, according to Bison's
1487 * LALR(1) parser algorithm.
1488 *
1489 * This function is given a Bison parser symbol stack, reflecting the parser's
1490 * entire state at a certain point, i.e. when a syntax error occured. This
1491 * function will then walk ahead the potential parse tree starting from the
1492 * current head of the given symbol stack. This function will call itself
1493 * recursively to scan the individual parse tree branches. As soon as it hits
1494 * on the next non-terminal grammar symbol in one parse tree branch, it adds the
1495 * found non-terminal symbol to @a expectedSymbols and aborts scanning the
1496 * respective tree branch further. If any local parser state is reached a second
1497 * time, the respective parse tree is aborted to avoid any endless recursion.
1498 *
1499 * @param stack - current Bison (yacc) symbol stack to be examined
1500 * @param expectedSymbols - will be filled with next expected grammar symbols
1501 * @param nextExpectedChars - just for internal purpose, due to the recursive
1502 * implementation of this function, do supply an
1503 * empty string for this argument
1504 * @param history - only for internal purpose, keeps a history of all previous
1505 * parser symbol stacks (just for avoiding endless recursion in
1506 * this recursive algorithm), do supply an empty history
1507 * @param depth - just for internal debugging purposes, do not supply it
1508 */
1509 static void walkAndFillExpectedSymbols(
1510 std::vector<YYTYPE_INT16>& stack,
1511 std::map<String,BisonSymbolInfo>& expectedSymbols,
1512 String& nextExpectedChars, YYStackHistory& history, int depth = 0)
1513 {
1514 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1515 printf("\n");
1516 for (int i = 0; i < depth; ++i) printf("\t");
1517 printf("Symbol stack:");
1518 for (int i = 0; i < stack.size(); ++i) {
1519 printf(" %d", stack[i]);
1520 }
1521 printf("\n");
1522 #endif
1523 startLabel:
1524
1525 // detect endless recursion
1526 if (history.count(stack)) return;
1527 history.insert(stack);
1528
1529 if (stack.empty()) {
1530 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1531 for (int i = 0; i < depth; ++i) printf("\t");
1532 printf("(EMPTY STACK)\n");
1533 #endif
1534 return;
1535 }
1536
1537 int state = stack[stack.size() - 1];
1538 int n = yypact[state];
1539 if (n == YYPACT_NINF) { // default reduction required ...
1540 // get default reduction rule for this state
1541 n = yydefact[state];
1542 if (n <= 0 || n >= YYNRULES) {
1543 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1544 for (int i = 0; i < depth; ++i) printf("\t");
1545 printf("(EMPTY RULE)\n");
1546 #endif
1547 return; // no rule, something is wrong
1548 }
1549 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1550 for (int i = 0; i < depth; ++i) printf("\t");
1551 printf("(default reduction)\n");
1552 #endif
1553 #if HAVE_BISON_MAJ >= 3
1554 if (!nextExpectedChars.empty() || !_isRuleTerminalSymbol(n, stack)) {
1555 #else
1556 if (!nextExpectedChars.empty() || !_isRuleTerminalSymbol(n)) {
1557 #endif
1558 // Return the new resolved expected symbol (left-hand symbol of grammar
1559 // rule), then we're done in this state. (If the same symbol can be
1560 // matched on different ways, then it is non-terminal symbol.)
1561 bool ambigious =
1562 expectedSymbols.count(yytname[yyr1[n]]) &&
1563 expectedSymbols[yytname[yyr1[n]]].nextExpectedChars != nextExpectedChars;
1564 #if HAVE_BISON_MAJ >= 3
1565 expectedSymbols[yytname[yyr1[n]]] = _symbolInfoForRule(n, stack, nextExpectedChars);
1566 #else
1567 expectedSymbols[yytname[yyr1[n]]] = _symbolInfoForRule(n, nextExpectedChars);
1568 #endif
1569 if (ambigious)
1570 expectedSymbols[yytname[yyr1[n]]].isTerminalSymbol = false;
1571 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1572 for (int i = 0; i < depth; ++i) printf("\t");
1573 printf("(empty expectedChars. sym = %s)\n", yytname[yyr1[n]]);
1574 #endif
1575 return;
1576 }
1577 _yyReduce(stack, n);
1578 goto startLabel;
1579 }
1580 if (!(YYPACT_NINF < n && n <= YYLAST)) {
1581 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1582 for (int i = 0; i < depth; ++i) printf("\t");
1583 printf("(invalid action B)\n");
1584 #endif
1585 return;
1586 }
1587
1588 // Check for duplicate states, if duplicates exist return
1589 // (this check is necessary since the introduction of the yyValid() call
1590 // below, which does not care about duplicates).
1591 for (int i = 0; i < stack.size(); ++i)
1592 for (int k = i + 1; k < stack.size(); ++k)
1593 if (stack[i] == stack[k])
1594 return;
1595
1596 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1597 for (int i = 0; i < depth; ++i) printf("\t");
1598 printf("Expected tokens:");
1599 #endif
1600 int begin = n < 0 ? -n : 0;
1601 //int checklim = YYLAST - n + 1;
1602 int end = YYNTOKENS;//checklim < YYNTOKENS ? checklim : YYNTOKENS;
1603 int rule, action, stackSize, nextExpectedCharsLen;
1604 for (int token = begin; token < end; ++token) {
1605 if (token <= YYTERROR) continue;
1606 if (yytname[token] == String("$undefined")) continue;
1607 if (yytname[token] == String("EXT_ASCII_CHAR")) continue;
1608 //if (yycheck[n + token] != token) goto default_reduction;
1609 if (yycheck[n + token] != token) { // default reduction suggested ...
1610 // If we are here, it means the current token in the loop would not
1611 // cause a "shift", however we don't already know whether this token
1612 // is valid or not. Because there might be several reductions
1613 // involved until one can determine whether the token causes an
1614 // error or is valid. So we use this heavy check instead:
1615 std::vector<YYTYPE_INT16> stackCopy = stack; // copy required, since reduction will take place
1616 if (!yyValid(stackCopy, _tokenChar(token))) continue; // invalid token
1617 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1618 printf(" ETdr(%s)", yytname[token]);
1619 #endif
1620 // the token is valid, "stackCopy" has been reduced accordingly
1621 // and now do recurse ...
1622 nextExpectedChars += _tokenName(token);
1623 nextExpectedCharsLen = nextExpectedChars.size();
1624 walkAndFillExpectedSymbols( //FIXME: could cause stack overflow (should be a loop instead), is probably fine with our current grammar though
1625 stackCopy, expectedSymbols, nextExpectedChars, history, depth + 1
1626 );
1627 nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'
1628 continue;
1629 }
1630 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1631 printf(" ET(%s)", yytname[token]);
1632 #endif
1633
1634 action = yytable[n + token];
1635 if (action == 0 || action == YYTABLE_NINF) {
1636 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1637 printf(" (invalid action A) "); fflush(stdout);
1638 #endif
1639 continue; // error, ignore
1640 }
1641 if (action < 0) { // reduction with rule -action required ...
1642 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1643 printf(" (reduction) "); fflush(stdout);
1644 #endif
1645 rule = -action;
1646 goto reduce;
1647 }
1648 if (action == YYFINAL) {
1649 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1650 printf(" (ACCEPT) "); fflush(stdout);
1651 #endif
1652 continue; // "accept" state, we don't care about it here
1653 }
1654
1655 // "shift" required ...
1656
1657 if (std::find(stack.begin(), stack.end(), action) != stack.end()) {
1658 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1659 printf(" (duplicate state %d) ", action); fflush(stdout);
1660 #endif
1661 continue; // duplicate state, ignore it to avoid endless recursions
1662 }
1663
1664 // "shift" / push the new state on the symbol stack and call this
1665 // function recursively, and restore the stack after the recurse return
1666 stackSize = stack.size();
1667 nextExpectedCharsLen = nextExpectedChars.size();
1668 stack.push_back(action);
1669 nextExpectedChars += _tokenName(token);
1670 walkAndFillExpectedSymbols( //FIXME: could cause stack overflow (should be a loop instead), is probably fine with our current grammar though
1671 stack, expectedSymbols, nextExpectedChars, history, depth + 1
1672 );
1673 stack.resize(stackSize); // restore stack
1674 nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'
1675 continue;
1676
1677 //default_reduction: // resolve default reduction for this state
1678 // printf(" (default red.) "); fflush(stdout);
1679 // rule = yydefact[state];
1680
1681 reduce: // "reduce" required
1682 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1683 printf(" (reduce by %d) ", rule); fflush(stdout);
1684 #endif
1685 if (rule == 0 || rule >= YYNRULES) {
1686 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1687 printf(" (invalid rule) "); fflush(stdout);
1688 #endif
1689 continue; // invalid rule, something is wrong
1690 }
1691 // Store the left-hand symbol of the grammar rule. (If the same symbol
1692 // can be matched on different ways, then it is non-terminal symbol.)
1693 bool ambigious =
1694 expectedSymbols.count(yytname[yyr1[rule]]) &&
1695 expectedSymbols[yytname[yyr1[rule]]].nextExpectedChars != nextExpectedChars;
1696 #if HAVE_BISON_MAJ >= 3
1697 expectedSymbols[yytname[yyr1[rule]]] = _symbolInfoForRule(rule, stack, nextExpectedChars);
1698 #else
1699 expectedSymbols[yytname[yyr1[rule]]] = _symbolInfoForRule(rule, nextExpectedChars);
1700 #endif
1701 if (ambigious)
1702 expectedSymbols[yytname[yyr1[n]]].isTerminalSymbol = false;
1703 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1704 printf(" (SYM %s) ", yytname[yyr1[rule]]); fflush(stdout);
1705 #endif
1706 }
1707 #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1708 printf("\n");
1709 #endif
1710 }
1711
1712 /**
1713 * Just a convenience wrapper on top of the actual walkAndFillExpectedSymbols()
1714 * implementation above, which can be called with less parameters than the
1715 * implementing function above actually requires.
1716 */
1717 static void walkAndFillExpectedSymbols(
1718 std::vector<YYTYPE_INT16>& stack,
1719 std::map<String,BisonSymbolInfo>& expectedSymbols)
1720 {
1721 String nextExpectedChars;
1722 YYStackHistory history;
1723
1724 walkAndFillExpectedSymbols(
1725 stack, expectedSymbols, nextExpectedChars, history
1726 );
1727 }
1728
1729 #define DEBUG_PUSH_PARSE 0
1730
1731 /**
1732 * Implements parsing exactly one character (given by @a ch), continueing at the
1733 * parser position reflected by @a stack. The @a stack will hold the new parser
1734 * state after this call.
1735 *
1736 * This function is implemented according to Bison's LALR(1) parser algorithm.
1737 */
1738 static bool yyPushParse(std::vector<YYTYPE_INT16>& stack, char ch) {
1739 startLabel:
1740
1741 #if DEBUG_PUSH_PARSE
1742 //printf("\n");
1743 //for (int i = 0; i < depth; ++i) printf("\t");
1744 printf("Symbol stack:");
1745 for (int i = 0; i < stack.size(); ++i) {
1746 printf(" %d", stack[i]);
1747 }
1748 printf(" char='%c'(%d)\n", ch, (int)ch);
1749 #endif
1750
1751 if (stack.empty()) return false;
1752
1753 int state = stack.back();
1754 int n = yypact[state];
1755 if (n == YYPACT_NINF) { // default reduction required ...
1756 #if DEBUG_PUSH_PARSE
1757 printf("(def reduce 1)\n");
1758 #endif
1759 state = _yyDefaultReduce(stack);
1760 goto startLabel;
1761 }
1762 if (!(YYPACT_NINF < n && n <= YYLAST)) return false;
1763
1764 YYTYPE_INT16 token = (ch == YYEOF) ? YYEOF : yytranslate[ch];
1765 n += token;
1766 if (n < 0 || YYLAST < n || yycheck[n] != token) {
1767 #if DEBUG_PUSH_PARSE
1768 printf("(def reduce 2) n=%d token=%d\n", n, token);
1769 #endif
1770 state = _yyDefaultReduce(stack);
1771 goto startLabel;
1772 }
1773 int action = yytable[n]; // yytable[yypact[state] + token]
1774 if (action == 0 || action == YYTABLE_NINF) throw 4;
1775 if (action < 0) {
1776 #if DEBUG_PUSH_PARSE
1777 printf("(reduce)\n");
1778 #endif
1779 int rule = -action;
1780 state = _yyReduce(stack, rule);
1781 goto startLabel;
1782 }
1783 if (action == YYFINAL) return true; // final state reached
1784
1785 #if DEBUG_PUSH_PARSE
1786 printf("(push)\n");
1787 #endif
1788 // push new state
1789 state = action;
1790 stack.push_back(state);
1791 return true;
1792 }
1793
1794 /**
1795 * Returns true if parsing ahead with given character @a ch is syntactically
1796 * valid according to the LSCP grammar, it returns false if it would create a
1797 * parse error.
1798 *
1799 * The @a stack will reflect the new parser state after this call.
1800 *
1801 * This is just a wrapper ontop of yyPushParse() which converts parser
1802 * exceptions thrown by yyPushParse() into @c false return value.
1803 */
1804 static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch) {
1805 try {
1806 return yyPushParse(stack, ch);
1807 } catch (int i) {
1808 #if DEBUG_PUSH_PARSE
1809 printf("exception %d\n", i);
1810 #endif
1811 return false;
1812 } catch (...) {
1813 return false;
1814 }
1815 }
1816
1817 /**
1818 * Returns the amount of correct characters of given @a line from the left,
1819 * according to the LSCP grammar.
1820 *
1821 * @param stack - a Bison symbol stack to work with
1822 * @param line - the input line to check
1823 * @param bAutoCorrect - if true: try to correct obvious, trivial syntax errors
1824 */
1825 static int yyValidCharacters(std::vector<YYTYPE_INT16>& stack, String& line, bool bAutoCorrect) {
1826 int i;
1827 for (i = 0; i < line.size(); ++i) {
1828 // since we might check the same parser state twice against the current
1829 // char here below, and since the symbol stack might be altered
1830 // (i.e. shifted or reduced) on syntax errors, we have to backup the
1831 // current symbol stack and restore it on syntax errors below
1832 std::vector<YYTYPE_INT16> stackCopy = stack;
1833 if (yyValid(stackCopy, line[i])) {
1834 stack = stackCopy;
1835 continue;
1836 }
1837 if (bAutoCorrect) {
1838 // try trivial corrections, i.e. upper case character instead of
1839 // lower case, subline instead of space and vice versa
1840 char c;
1841 if (line[i] == ' ') c = '_';
1842 else if (line[i] == '_') c = ' ';
1843 else if (isLowerCaseAlphaChar(line[i]))
1844 c = alphaCharToUpperCase(line[i]);
1845 else return i;
1846 if (yyValid(stack, c)) {
1847 line[i] = c;
1848 continue;
1849 }
1850 }
1851 return i;
1852 }
1853 return i;
1854 }
1855
1856 /**
1857 * Should only be called on syntax errors: returns a set of non-terminal
1858 * symbols expected to appear now/next, just at the point where the syntax
1859 * error appeared.
1860 *
1861 * @returns names of the non-terminal symbols expected at this parse position
1862 */
1863 static std::set<String> yyExpectedSymbols() {
1864 std::map<String,BisonSymbolInfo> expectedSymbols;
1865 yyparse_param_t* param = GetCurrentYaccSession();
1866 YYTYPE_INT16* ss = (*param->ppStackBottom);
1867 YYTYPE_INT16* sp = (*param->ppStackTop);
1868 int iStackSize = sp - ss + 1;
1869 // copy and wrap parser's symbol stack into a convenient STL container
1870 std::vector<YYTYPE_INT16> stack;
1871 for (int i = 0; i < iStackSize; ++i) {
1872 stack.push_back(ss[i]);
1873 }
1874 // do the actual parser work
1875 walkAndFillExpectedSymbols(stack, expectedSymbols);
1876
1877 // convert expectedSymbols to the result set
1878 std::set<String> result;
1879 for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1880 it != expectedSymbols.end(); ++it) result.insert(it->first);
1881 return result;
1882 }
1883
1884 #define DEBUG_YY_AUTO_COMPLETE 0
1885
1886 /**
1887 * Generates and returns an auto completion string for the current parser
1888 * state given by @a stack. That means, this function will return the longest
1889 * sequence of characters that is uniqueley expected to be sent next by the LSCP
1890 * client. Or in other words, if the LSCP client would send any other
1891 * character(s) than returned here, it would result in a syntax error.
1892 *
1893 * This function takes a Bison symbol @a stack as argument, reflecting the
1894 * current Bison parser state, and evaluates the individual grammar tree
1895 * branches starting from that particular position. It walks along the grammar
1896 * tree as long as there is only one possible tree branch and assembles a string
1897 * of input characters that would lead to that walk through the grammar tree. As
1898 * soon as a position in the grammar tree is reached where there are multiple
1899 * possible tree branches, this algorithm will stop, since the user could have
1900 * multiple possible valid characters he could type at that point, thus auto
1901 * completion would no longer be unique at that point.
1902 *
1903 * Regarding @a history argument: read the description on YYStackHistory for the
1904 * purpose behind this argument.
1905 *
1906 * @param stack - current Bison (yacc) symbol stack to create auto completion for
1907 * @param history - only for internal purpose, keeps a history of all previous
1908 * parser symbol stacks (just for avoiding endless recursion in
1909 * this auto completion algorithm), do supply an empty history
1910 * @param depth - just for internal debugging purposes, do not supply anything
1911 * @returns auto completion for current, given parser state
1912 */
1913 static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack, YYStackHistory& history, int depth = 0) {
1914 std::map<String,BisonSymbolInfo> expectedSymbols;
1915 walkAndFillExpectedSymbols(stack, expectedSymbols);
1916 if (expectedSymbols.size() == 1) {
1917 String name = expectedSymbols.begin()->first;
1918 BisonSymbolInfo info = expectedSymbols.begin()->second;
1919 #if DEBUG_YY_AUTO_COMPLETE
1920 for (int q = 0; q < depth; ++q) printf(" ");
1921 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());
1922 #endif
1923 if (info.nextExpectedChars.empty() || !info.isTerminalSymbol) return "";
1924 // parse forward with the suggested auto completion
1925 std::vector<YYTYPE_INT16> stackCopy = stack;
1926 yyValidCharacters(stackCopy, info.nextExpectedChars, false);
1927 // detect endless recursion
1928 if (history.count(stackCopy)) return "";
1929 history.insert(stackCopy);
1930 // recurse and return the expanded auto completion with maximum length
1931 return info.nextExpectedChars + yyAutoComplete(stackCopy, history, depth + 1);
1932 } else if (expectedSymbols.size() == 0) {
1933 #if DEBUG_YY_AUTO_COMPLETE
1934 for (int q = 0; q < depth; ++q) printf(" ");
1935 printf("(%d) No sub suggestion.\n", depth);
1936 #endif
1937 return "";
1938 } else if (expectedSymbols.size() > 1) {
1939 #if DEBUG_YY_AUTO_COMPLETE
1940 for (int q = 0; q < depth; ++q) printf(" ");
1941 printf("(%d) Multiple sub possibilities (before expansion):", depth);
1942 for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1943 it != expectedSymbols.end(); ++it)
1944 {
1945 printf(" %s (..%s)", it->first.c_str(), it->second.nextExpectedChars.c_str());
1946 }
1947 printf("\n");
1948 #endif
1949 // check if any of the possibilites is a non-terminal symbol, if so, we
1950 // have no way for auto completion at this point
1951 for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1952 it != expectedSymbols.end(); ++it)
1953 {
1954 if (!it->second.isTerminalSymbol) {
1955 #if DEBUG_YY_AUTO_COMPLETE
1956 for (int q = 0; q < depth; ++q) printf(" ");
1957 printf("(%d) Non-terminal exists. Stop.", depth);
1958 #endif
1959 return "";
1960 }
1961 }
1962 #if 0 // commented out for now, since practically irrelevant and VERY slow ...
1963 // all possibilities are terminal symbols, so expand all possiblities to
1964 // maximum length with a recursive call for each possibility
1965 for (std::map<String,BisonSymbolInfo>::iterator it = expectedSymbols.begin();
1966 it != expectedSymbols.end(); ++it)
1967 {
1968 if (it->second.nextExpectedChars.empty() || !it->second.isTerminalSymbol) continue;
1969 // parse forward with this particular suggested auto completion
1970 std::vector<YYTYPE_INT16> stackCopy = stack;
1971 yyValidCharacters(stackCopy, it->second.nextExpectedChars, false);
1972 // detect endless recursion
1973 if (history.count(stackCopy)) continue;
1974 history.insert(stackCopy);
1975 // recurse and return the total possible auto completion for this
1976 // grammar tree branch
1977 it->second.nextExpectedChars += yyAutoComplete(stackCopy, history, depth + 1);
1978 }
1979 #endif
1980 // try to find the longest common string all possibilities start with
1981 // (from the left)
1982 String sCommon;
1983 for (int i = 0; true; ++i) {
1984 char c;
1985 for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1986 it != expectedSymbols.end(); ++it)
1987 {
1988 if (i >= it->second.nextExpectedChars.size())
1989 goto commonSearchEndLabel;
1990 if (it == expectedSymbols.begin())
1991 c = it->second.nextExpectedChars[i];
1992 if (c != it->second.nextExpectedChars[i])
1993 goto commonSearchEndLabel;
1994 if (it == --expectedSymbols.end())
1995 sCommon += c;
1996 }
1997 }
1998 commonSearchEndLabel:
1999 #if DEBUG_YY_AUTO_COMPLETE
2000 for (int q = 0; q < depth; ++q) printf(" ");
2001 printf("(%d) Multiple sub possibilities (after expansion):", depth);
2002 for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
2003 it != expectedSymbols.end(); ++it)
2004 {
2005 printf(" %s (..%s)", it->first.c_str(), it->second.nextExpectedChars.c_str());
2006 }
2007 printf("\n");
2008 for (int q = 0; q < depth; ++q) printf(" ");
2009 printf("(%d) Common sub possibility: '%s'\n", depth, sCommon.c_str());
2010 #endif
2011 return sCommon;
2012 }
2013 return ""; // just pro forma, should never happen though
2014 }
2015
2016 /**
2017 * Just a convenience wrapper on top of the actual yyAutoComplete()
2018 * implementation. See its description above for details.
2019 */
2020 static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack) {
2021 YYStackHistory history;
2022 return yyAutoComplete(stack, history);
2023 }
2024
2025 namespace LinuxSampler {
2026
2027 #define DEBUG_SHELL_INTERACTION 0
2028
2029 /**
2030 * If LSCP shell mode is enabled for the respective LSCP client connection, then
2031 * this function is called on every new byte received from that client. It will
2032 * check the current total input line and reply to the LSCP shell with a
2033 * specially crafted string, which allows the shell to provide colored syntax
2034 * highlighting and potential auto completion in the shell.
2035 *
2036 * It also performs auto correction of obvious & trivial syntax mistakes if
2037 * requested.
2038 *
2039 * The return value of this function will be sent to the client. It contains one
2040 * line specially formatted for the LSCP shell application, which can easily be
2041 * processed by the client/shell for extracting its necessary informations like
2042 * which part of the current command line is syntactically correct, which part
2043 * is incorrect, what could be auto completed right now, etc. So all the heavy
2044 * grammar evaluation tasks are peformed by the LSCP server for the LSCP shell
2045 * application (which is desgined as a thin client), so the LSCP shell
2046 * application will only have to show the results of the LSCP server's
2047 * evaluation to the user on the screen.
2048 *
2049 * @param line - the current command line to be evaluated by LSCP parser
2050 * @param param = reentrant parser session parameters
2051 * @param possibilities - whether all possibilities shall be shown
2052 * @returns LSCP shell response line to be returned to the client
2053 */
2054 String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param, bool possibilities) {
2055 // first, determine how many characters (starting from the left) of the
2056 // given input line are already syntactically correct
2057 std::vector<YYTYPE_INT16> stack;
2058 stack.push_back(0); // every Bison symbol stack starts with state zero
2059 String l = line + '\n'; // '\n' to pretend ENTER as if the line was now complete
2060 int n = yyValidCharacters(stack, l, param->bShellAutoCorrect);
2061
2062 // if auto correction is enabled, apply the auto corrected string to
2063 // intput/output string 'line'
2064 if (param->bShellAutoCorrect) {
2065 int nMin = (n < line.length()) ? n : line.length();
2066 line.replace(0, nMin, l.substr(0, nMin));
2067 }
2068
2069 size_t cursorPos = line.size() + param->iCursorOffset;
2070 if (cursorPos < 0) cursorPos = 0;
2071
2072 // generate an info string that will be sent to the LSCP shell for letting
2073 // it know which part is correct, which one is wrong, where is the cursor, etc.
2074 String result = line;
2075 result.insert(n <= result.length() ? n : result.length(), LSCP_SHK_GOOD_FRONT);
2076 result.insert(cursorPos <= n ? cursorPos : cursorPos + String(LSCP_SHK_GOOD_FRONT).length(), LSCP_SHK_CURSOR);
2077 int code = (n > line.length()) ? LSCP_SHU_COMPLETE : (n < line.length()) ?
2078 LSCP_SHU_SYNTAX_ERR : LSCP_SHU_INCOMPLETE;
2079 result = "SHU:" + ToString(code) + ":" + result;
2080 //if (n > line.length()) result += " [OK]";
2081
2082 // get a clean parser stack to the last valid parse position
2083 // (due to the appended '\n' character above, and on syntax errors, the
2084 // symbol stack might be in undesired, i.e. reduced state)
2085 stack.clear();
2086 stack.push_back(0); // every Bison symbol stack starts with state zero
2087 l = line.substr(0, n);
2088 if (!l.empty()) yyValidCharacters(stack, l, param->bShellAutoCorrect);
2089
2090 // generate auto completion suggestion (based on the current parser stack)
2091 std::vector<YYTYPE_INT16> stackCopy = stack; // make a copy, since yyAutoComplete() might alter the stack
2092 String sSuggestion = yyAutoComplete(stackCopy);
2093 if (!sSuggestion.empty()) result += LSCP_SHK_SUGGEST_BACK + sSuggestion;
2094
2095 if (possibilities) {
2096 // append all possible terminals and non-terminals according to
2097 // current parser state
2098 std::map<String,BisonSymbolInfo> expectedSymbols;
2099 walkAndFillExpectedSymbols(stack, expectedSymbols);
2100
2101 // pretend to LSCP shell that the following terminal symbols were
2102 // non-terminal symbols (since they are not human visible for auto
2103 // completion on the shell's screen)
2104 std::set<String> specialNonTerminals;
2105 specialNonTerminals.insert("SP");
2106 specialNonTerminals.insert("CR");
2107 specialNonTerminals.insert("LF");
2108
2109 String sPossibilities;
2110 int iNonTerminals = 0;
2111 int iTerminals = 0;
2112 for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
2113 it != expectedSymbols.end(); ++it)
2114 {
2115 if (!sPossibilities.empty()) sPossibilities += " | ";
2116 if (it->second.isTerminalSymbol && !specialNonTerminals.count(it->first)) {
2117 sPossibilities += it->first;
2118 iTerminals++;
2119 } else {
2120 sPossibilities += "<" + it->first + ">";
2121 iNonTerminals++;
2122 }
2123 }
2124 if (!sPossibilities.empty() && (iNonTerminals || iTerminals > 1)) {
2125 result += LSCP_SHK_POSSIBILITIES_BACK + sPossibilities;
2126 }
2127 }
2128
2129 #if DEBUG_SHELL_INTERACTION
2130 printf("%s\n", result.c_str());
2131 #endif
2132
2133 return result;
2134 }
2135
2136 /**
2137 * Clears input buffer.
2138 */
2139 void restart(yyparse_param_t* pparam, int& yychar) {
2140 bytes = 0;
2141 ptr = 0;
2142 sLastError = "";
2143 sParsed = "";
2144 }
2145
2146 }

  ViewVC Help
Powered by ViewVC