Вам нужно написать свой парсер рекурсивного спуска из вашего BNF / EBNF. Недавно мне пришлось написать свое, и эта страница очень помогла. Я не уверен, что вы подразумеваете под "просто кодом". Вы хотите знать, как написать свой собственный рекурсивный парсер?
Если вы хотите это сделать, вам нужно сначала установить грамматику. Если у вас есть EBNF / BNF, парсер может быть легко записан с него.
Первое, что я сделал, когда написал свой синтаксический анализатор, - прочитал все и затем токенизировал текст. Таким образом, я получил массив токенов, которые я рассматривал как стек. Чтобы уменьшить многословность / накладные расходы при извлечении значения из стека и последующем его повторном включении, если оно вам не нужно, вы можете использовать метод peek
, который просто возвращает верхнее значение в стеке, не извлекая его.
UPDATE
Исходя из вашего комментария, мне пришлось написать анализатор с рекурсивным спуском в Javascript с нуля. Вы можете взглянуть на парсер здесь . Просто найдите функцию constraints
. Я написал свою собственную tokenize
функцию для токенизации ввода. Я также написал другую вспомогательную функцию (peek
, о которой я упоминал ранее). Парсер разбирает по EBNF здесь .
Мне потребовалось немного времени, чтобы понять, потому что прошло много лет с тех пор, как я написал парсер (последний раз, когда я писал, что это было в школе!), Но поверьте мне, как только вы получите это, вы получите Это. Я надеюсь, что мой пример поможет вам продвинуться дальше.
ДРУГОЕ ОБНОВЛЕНИЕ
Я также понял, что мой пример может быть не тем, что вы хотите, потому что вы можете использовать парсер с уменьшением смещения. Вы упомянули, что прямо сейчас вы пытаетесь написать токенизатор. В моем случае я написал свой собственный токенайзер на Javascript. Это, вероятно, не надежно, но этого было достаточно для моих нужд.
function tokenize(options) {
var str = options.str;
var delimiters = options.delimiters.split("");
var returnDelimiters = options.returnDelimiters || false;
var returnEmptyTokens = options.returnEmptyTokens || false;
var tokens = new Array();
var lastTokenIndex = 0;
for(var i = 0; i < str.length; i++) {
if(exists(delimiters, str[i])) {
var token = str.substring(lastTokenIndex, i);
if(token.length == 0) {
if(returnEmptyTokens) {
tokens.push(token);
}
}
else {
tokens.push(token);
}
if(returnDelimiters) {
tokens.push(str[i]);
}
lastTokenIndex = i + 1;
}
}
if(lastTokenIndex < str.length) {
var token = str.substring(lastTokenIndex, str.length);
token = token.replace(/^\s+/, "").replace(/\s+$/, "");
if(token.length == 0) {
if(returnEmptyTokens) {
tokens.push(token);
}
}
else {
tokens.push(token);
}
}
return tokens;
}
Исходя из вашего кода, похоже, что вы одновременно читаете, токенизируете и анализируете - я предполагаю, что это то, что делает парсер с уменьшением сдвига? Поток того, что у меня есть, - сначала токенизировать, чтобы построить стек токенов, а затем отправить токены через парсер рекурсивного спуска.