fork download
  1. Не, ты делаешь неправильно. Суть метода рекурсивного спуска в том, что мы для каждой конструкции пишем свою функцию для разбора, при этом спускаясь от больших конструкций (текст с тегами) к меньшим (отдельный тег). Для начала надо определиться с грамматикой, то есть правилами, что может встретиться в тексте.
  2.  
  3. Символ | у меня значит «или». x значит «может встретиться столько-то раз»
  4.  
  5. СложныйТекст = (ПарныйТег | ПростоТекст) x 0 .. N
  6. ПарныйТег = ОткрывающийТег СложныйТекст ЗакрывающийТег
  7. ОткрывающийТег = ...
  8. ЗакрывающийТег = последовательность [ /name ]
  9. ПростойТекст = (любые токены кроме [)
  10.  
  11. Смотри, более сложные конструкции состоят из более простых. Это спуск. При этом более простая конструкция (парныйТег) может содержать более сложную (СложныйТекст). Это рекурсия.
  12.  
  13. Нам надо сделать на каждую конструкцию выше свою функцию для разбора. То есть будут функции
  14.  
  15. парситьСложныйТекст()
  16. парситьПарныйТег()
  17. .....
  18.  
  19. При этом каждая функция создает и возвращает узел дерева или массив узлов. Ну функция парситьЗакрывающийТег() может возвращать не узел, а просто название того тега, что она там распарсила.
  20.  
  21. Вот пример парсинга ПростогоТекста. ПростойТекст — это любые токены, кроме токена [ который открывает тег. Напишем метод:
  22.  
  23. парситьПростойТекст()
  24. {
  25. токены = [];
  26. пока (текущий токен не равен [) {
  27. т = прочитатьТекущийТокен();
  28. добавить т в массив токены;
  29. }
  30.  
  31. вернуть новый ТекстовыйУзел(токены);
  32. }
  33.  
  34. Напишем еще метод:
  35.  
  36. парситьПарныйТег()
  37. {
  38. узел = парситьОткрывающийТег();
  39.  
  40. содержимое = парситьСложныйТекст();
  41. узел.добавитьДетей(содержимое);
  42.  
  43. название = парситьЗакрывающийТег();
  44. если (название не совпадает с названием узла) то { ошибка;}
  45.  
  46. вернуть узел;
  47. }
  48.  
  49. Вот как-то так.
Success #stdin #stdout 0.01s 20520KB
stdin
Standard input is empty
stdout
Не, ты делаешь неправильно. Суть метода рекурсивного спуска в том, что мы для каждой конструкции пишем свою функцию для разбора, при этом спускаясь от больших конструкций (текст с тегами) к меньшим (отдельный тег). Для начала надо определиться с грамматикой, то есть правилами, что может встретиться в тексте.

Символ | у меня значит «или». x значит «может встретиться столько-то раз»

СложныйТекст = (ПарныйТег | ПростоТекст) x 0 .. N
ПарныйТег = ОткрывающийТег СложныйТекст ЗакрывающийТег
ОткрывающийТег = ... 
ЗакрывающийТег = последовательность [ /name ]
ПростойТекст = (любые токены кроме [)

Смотри, более сложные конструкции состоят из более простых. Это спуск. При этом более простая конструкция (парныйТег) может содержать более сложную (СложныйТекст). Это рекурсия.

Нам надо сделать на каждую конструкцию выше свою функцию для разбора. То есть будут функции

парситьСложныйТекст()
парситьПарныйТег()
.....

При этом каждая функция создает и возвращает узел дерева или массив узлов. Ну функция парситьЗакрывающийТег() может возвращать не узел, а просто название того тега, что она там распарсила.

Вот пример парсинга ПростогоТекста. ПростойТекст — это любые токены, кроме токена [ который открывает тег. Напишем метод:

парситьПростойТекст()
{
токены = [];
пока (текущий токен не равен [) {
т = прочитатьТекущийТокен();
добавить т в массив токены;
}

вернуть новый ТекстовыйУзел(токены);
}

Напишем еще метод: 

парситьПарныйТег()
{
узел = парситьОткрывающийТег();

содержимое  = парситьСложныйТекст();
узел.добавитьДетей(содержимое);

название = парситьЗакрывающийТег();
если (название не совпадает с названием узла)  то { ошибка;}

вернуть узел;
}

Вот как-то так.