Конференція VBStreets - Перегляд теми - Інтерпретатор команд
Весь смак програмування!
- Список форумів‹ Visual Basic‹ Visual Basic 1–6
- Змінити розмір шрифту
- FAQ
- Вхід
Інтерпретатор команд
Інтерпретатор команд
Re: Інтерпретатор команд
Re: Інтерпретатор команд
Re: Інтерпретатор команд
Re: Інтерпретатор команд
Re: Інтерпретатор команд
Re: Інтерпретатор команд
Ууу, ну це справа така. Написати свій інтерпретатор – це перший крок до написання свого компілятора.
Взагалі, завдання можна розбити на два завдання: парсер • обробник команд
Ось зразковий код парсера Код: Виділити все A1 = Split(InputFile, vbCrLf) 'Якщо для розділення рядків використовуємо новий рядок. Або: A1 = Split(InputFile, ";") ' Для паскалеподібного синтаксису.
Потім, маючи в масиві A1 ключові слова нашого скрипта з параметрами, так? Якщо з параметрами то додатково сплітуємо кожен елемент масиву за ознакою, що розділяє параметри, тобто по пробілу.
Тепер код оброблювача команд. Це найпростіший командний процесор з уроків інформатики: Для початку приклад скрипту:
Привітати_світ Записати_в_реєстр HKCU Software\MySoft\Main LastUser Вася Сума 2 + 3 Показати_підсумок Вивести_повідомлення Заголовок vbOKOnly "Не знаю як, але парсер повинен вміти обробляти рядки, що містять прогалини"
Код: Виділити все 'Для другого рядка скрипта в масиві A2 наприклад, лежатиме: ' 0 1 2 3 4 '"Записати_в_реєстр", "HKCU", "Software\MySoft\Main", "LastUser", "Вася"
Select Case A2(0) Case "Записати_в_реєстр": Call Reeesr.Add(A2(1), A2(2), A2(3), A2(4)) 'робимо так Case "Привітати_світ": MsgBox("Helloworld!") Case "Вивести_повідомлення": MsgBox A2(1), A2(2), A2(3) Case "Сума": Ret = A2(1) + A2(3) case "Показати_підсумок": MsgBox Ret Case "Запустити": Shell A2(1), vbNormalFocus end Select
Тут я припускаю, що Reestr це клас, що працює з реєстром і має метод .Add(Key as string, Path as string, Name as String, Value as Variant), що додає запис до реєстру; що парсер якось реагує на лапки і сприймає все до наступної лапки (включаючи прогалини) як один параметр.
Re: Інтерпретатор команд
Re: Інтерпретатор команд
Re: Інтерпретатор команд
Денис, пиши правильні формулювання будь ласка.
Не «зразковий код парсера», а «приклад того, як ніколи не варто писати парсер».
Re: Інтерпретатор команд
Цікаво, а як правильніше?
1) Аналіз та розбиття коду на список простих операцій 2) Якщо використовуються модулі - перевірка їх наявності 3) Виконання команд зі списку ?
Re: Інтерпретатор команд
Ніхто не розбирає текст, код за допомогою сплітів та лефт-стрінгів. Це схоже на паяння тонкої електроніки розпеченим у багатті цвяхом.
Або ще одна шиза: використання регулярних виразів для цієї мети.
Re: Інтерпретатор команд
Навряд чи - швидше за все, просто незнання. Того ж Script-контролю за очі вистачить для його завдання.
Re: Інтерпретатор команд
Хакер писав(ла): Ніхто не розбирає текст, код за допомогою сплітів та лефт-стрінгів. Це схоже на паяння тонкої електроніки розпеченим у багатті цвяхом.
Або ще одна шиза: використання регулярних виразів для цієї мети.
Re: Інтерпретатор команд
Хакер писав(ла): Ніхто не розбирає текст, код за допомогою сплітів та лефт-стрінгів. Це схоже на пайку тонкуелектроніці розпеченим у багатті цвяхом.
Або ще одна шиза: використання регулярних виразів для цієї мети.
Маячня системника. Прикладне програмування загалом і високорівневі мови зокрема й створювалися у тому, щоб розбирати текст з допомогою сплітів і лефт-стрингов та інших зручних речей, які відволікають від основного задуму заморочками з розподілом пам'яті. І це схоже на паяння цвяхом, а схоже на перемикання конекторів і джамперів. А ось ваші методи, шановні системники, якраз схожі на пайку там, де можна обійтися стандартним конектором, або ще ось, як хтось казав, схожі на проектування зорельоту.
Парсер на мій приклад, це приклад як можна робити парсер. Залишаюсь при своїй думці.
Кому не подобається, напишіть свій приклад, як треба робити і як не треба робити.
Re: Інтерпретатор команд
Re: Інтерпретатор команд
Re: Інтерпретатор команд
Ти думаєш, що я тролю? А тобі не спадало на думку, що я справді так вважаю? Чи треба було явно додати абревіатуру "ІМХО"?
Re: Інтерпретатор команд
Re: Інтерпретатор команд
Re: Інтерпретатор команд
Re: Інтерпретатор команд
Наскільки я розумію, ці штуки організовуються за допомогою таблиці переходів, і деякі компілятори — наприклад, C# — створюють подібні конструкції автоматично, але в VB.Net і тим більше в старих версіях VB цього не передбачено. Чи можна провернути такий фокус вручну?
Re: Інтерпретатор команд
Re: Інтерпретатор команд
Ну по-перше "різні змінні та різна їх кількість" не відповідають принципу кінцевого автомата. Отже, завдання вже неправильно сформульовано. Якщо я правильно розумію описи (а це не факт)), тоспочатку в КА вводиться список ключових слів мови, що обробляється, а значить, ми відразу визначаємо набір майбутніх змінних. Потім ми обробляємо вхідні дані посимвольно (і кожен новий символ перекладає нас за словником від першої літери шуканого ключового слова до другої, третьої і т.д.) і щоразу, коли ми зустрічаємо ознаку кінця слова (банально пробіл), ми вже повинні мати в окремій змінній або індекс ключового слова зі словника, або значення, що відповідає помилці синтаксису (оскільки вхідне слово не знайдено у словнику). Далі, головна фішка КА – це режими (кінцеві стани), найпростіший режим – це помилка. у ньому виконання зупиняється та повідомляється номер рядка. все. а тепер припустимо, що наш автомат прочитав слово for. згідно зі своїми визначеннями мови, він переходить у режим циклу і очікує знайти ідентифікатор змінної, потім знак рівності, потім перше число, з якого розпочинати цикл, і так далі, далі, аж до самого next. коли автомату вдається знайти все, що він шукав, він викликає шаблон функції циклу і передає зібрані дані 1. Початок і кінець циклу, грубо кажучи, число ітерацій; 2. Список функцій, які треба виконувати в циклі; в окрему функцію. Ця функція також може стати частиною іншого циклу. І ось це все вишиковується в дерево.
Так ось, передавати дані з одного вузла дерева в інше безглуздо та небезпечно. Але в КА може бути суворо обмежений набір змінних (стек, мабуть), в який по-перше заносяться всі виявлені автоматично в тексті змінні, по-друге, свої, службові дані. Більше нічого не потрібно при правильній постановці завдання та правильної реалізації: Питання – відповідь; ключ – реакція. І нічого більше.
Ось що мене розлютило у відповідях Хакера, так цете, що Автор топіка попросив простий інтерпретатор кількох команд установки, копіювання, розпакування. Лінійний. Одноклітинний. Я йому дав такий алгоритм. Простий одноразовий прохід по тілу скрипта, зі строго регламентованим синтаксисом (ключове_слово параметр1.. параметрN)
Але ні, давайте стріляти з гармати по горобцях! Давайте! Нехай Автор топіка присвятить кілька років проектування своєї тьюрінг-повної мови програмування та компілятора до неї, нехай він обросте бородою та светром! Але замовник відмовиться від його послуг уже за тиждень.
Re: Інтерпретатор команд
Ось для такої нагоди і була моя відповідь. У цьому випадку використовувати спліт та Left$ - ідіотизм. Якщо йому потрібен аналог BAT-файлів, то точно скажу, що для обробки пакетного скрипта потрібно те, що я сказав.
Потім, у тебе поширена хвороба: «пахне розбором чогось і кінцевими автоматами — отже, потрібно імітувати бурхливу і складну діяльність». Хоча треба просто вирішувати завдання. Максимально простим і лінивим способом. Не для програміста-гаденя, а для комп'ютера.
Ось наприклад вб-шний спліт - це море непотрібної роботи зі створення копій фрагментів. Фрагментів може бути 100, значить і копій буде 100. Кожен фрагмент (копію) ти потім оброблятимеш знову піддавати спліту, і створиш для кожного фрагмента ще по 10 копій. Отже, буде вхідний код та 1100 копій його фрагментів. І це безглуздо і дико, тому що 1100 копій фрагментів нікому не потрібні: у них немає нічого нового (все вже є у вхідному коді), але вони пекло фрагментують рядкову купу. Це, напевно, саме той підхід, у дусі якого пишуться останні студії — тому вони так дико виснуть і повільно працюють.
Ось наприклад, при розподілі дільником ";" напевно вийде такий фрагмент: Код:Виділити все // І виходимо із функції FIRST, повертаючи 0 > функція SECOND() < while(bTruncated) < AsrLockThisItem()
Гарний фрагмент, так? Що таке розумне ти з ним зробиш після того, як отримаєш його сплітом?
Re: Інтерпретатор команд
Моє питання стосувалося саме того, про що я писав, - як оптимізувати блок Select Case, якщо всі умови мають форму порівняння з константою. Ні про що інше я не питав.
Спробую ще раз пояснити. Проблема з Select Case полягає в тому, що код: Код: Виділити все Select Case strCmd Case "Записати_в_реєстр": WriteReg Case "Привітати_світ": MsgBox "Hello world!" Case "Вивести_повідомлення": MsgBox A2(1), A2(2), A2(3) Case "Сума": Ret = A2(1) + A2(3) Case "Показати_підсумок": MsgBox Ret Case "Запустити": Shell A2(1), vbNormalFocus Case Else: MsgBox "Невідома команда" End Select компілюється в щось на зразок такого: Код: Виділити все If strCmd = "Записати_в_ре WriteReg ElseIf strCmd = "Привітати_світ" Then MsgBox "Hello world!" ElseIf strCmd = "Вивести_повідомлення" Then MsgBox A2(1), A2(2), A2(3 ) ElseIf strCmd = "Сума" Then Ret = A2(1) + A2(3) ElseIf strCmd = "Показати_підсумок" Then MsgBox Ret ElseIf strCmd = "Запустити" Then Shell A2(1), vbNormalFocus Else MsgBox "Невідома команда" End If тобто в довгу низку послідовних порівнянь. І це зрозуміло з огляду на те, що блоки Case можуть містити складні умови, такі як перевірка на належність кінцевому або нескінченному діапазону значень.
Однак у найпростішому випадку суворого порівняння з константами (точніше, зі значеннями, незмінними протягом всього блоку Select Case), хотілося б чогось такого: Код: Виділити все DimdicJumpTable As New Dictionary(Of String, Integer) dicJumpTable.Add("Записати_у_реєстр", 10) dicJumpTable.Add("Привітати_світ", 20) dicJumpTable.Add("Вивести_повідомлення", 30) dicJumpTable.Add("Сума", 40) dicJumpTable.Add("Показати_підсумок", 50) dicJumpTable.Add("Запустити", 60)
Do While тра-та-та
If dicJumpTable.ContainsKey(strCmd) Then GoSub dicJumpTable.Item(strCmd) Else MsgBox "Невідома команда" End If
10: WriteReg: Return 20: MsgBox "Hello world!": Return 30: MsgBox A2 (1), A2 (2), A2 (3): Return ) + A2(3): Return 50: MsgBox Ret: Return 60: Shell A2(1), vbNormalFocus: Return Якби такою оптимізацією займався сам компілятор Бейсіка, йому б нічого не варто було створити такий машинний код, де кожному Case-блоку відповідала маленька GoSub-підпрограма. Але якщо компілятор QB/VB/VB.Net такого не робить, чи є шанс зробити це за нього, не пускаючись у всі тяжкі із буквальним використанням оператора GoSub?
Повторюся, всі підпрограми, що викликаються, повинні мати доступ до всіх внутрішніх змінних поточної функції. Виклик зовнішніх функцій не підходить, тому що кожна підпрограма звертається до свого набору змінних, і загальна кількість цих змінних велика, щоб передавати всіх їх кожній функції, та й різнотипні вони всі, і з різною семантикою - в один масив не запхнеш.