/[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 2518 - (show annotations) (download)
Sat Feb 8 00:49:30 2014 UTC (10 years, 2 months ago) by schoenebeck
File size: 99737 byte(s)
* LSCP shell (WIP): added support for browsing the command
  history with up / down keys.
* LSCP server: fixed compilation error with Bison 3.x.
* Bumped version (1.0.0.svn31).

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

  ViewVC Help
Powered by ViewVC