#c #interpreter #basic
#c #интерпретатор #Базовые модели
Вопрос:
Я пытаюсь создать интерпретатор BASIC на C. Я начал с интерпретатора для математических вычислений (точно так же, как калькулятор, за исключением того, что здесь я могу присвоить переменной X значение 2, например). Моя проблема в том, что я не знаю, как заставить мой интерпретатор находить разницу между некоторыми входными данными. Например: 10 ПУСТЬ x = 10, это должно быть сохранено в массиве для последующего использования. ПУСТЬ x = 10, это должно быть выполнено мгновенно 10 1, это должно быть выполнено мгновенно.
Как мне модифицировать мой интерпретатор, чтобы он знал эти вещи? Я не знаю, где внести изменения, но я думаю, что это должно быть сделано в анализаторе, поэтому я публикую это здесь. Если вы хотите увидеть другой код, просто спросите.
//diddi
/*
* File: parser.c
* --------------
* This file implements a version of ReadExp that uses
* conventional precedence rules. Thus, the expression
*
* x = 2 * x y
*
* is interpreted as if it had been written
*
* x = ((2 * x) y))
*
* This language can be parsed using the following ambiguous
* grammar:
*
* E -> T
* E -> E op E
*
* T -> integer
* T -> identifier
* T -> ( E )
*
* Unfortunately, this grammar is not sufficient by itself. The
* parser must also provide some way to determine what operators
* take precedence over others. Moreover, it must avoid the
* problem of going into an infinite recursion of trying to read
* an expression by reading an expression, and so on forever.
*
* To solve these problems, this implementation passes a numeric
* value to the ReadE function that specifies the precedence
* level for the current subexpression. As long as ReadE finds
* operators with a higher precedence, it will read in those
* operators along with the following subexpression. If the
*
precedence of the new operator is the same or lower than
* the prevailing precedence, ReadE returns to the next higher
* level in the recursive-descent parsing and reads the operator
* there.
*/
#include <stdio.h>
#include <ctype.h>
#include "genlib.h"
#include "strlib.h"
#include "simpio.h"
#include "scanadt.h"
#include "parsering.h"
#include "exp.h"
#include "cmddisp.c"
/*
* Implementation notes: ParseExp
* ------------------------------
* This function just calls ReadE to read an expression and then
* checks to make sure no tokens are left over.
*/
expressionADT ParseExp(scannerADT scanner)
{
expressionADT exp;
exp = ReadE(scanner, 0);
if (MoreTokensExist(scanner)) {
Error("ParseExp: %s unexpected", ReadToken(scanner));
}
return (exp);
}
/*
* Implementation notes: ReadE
* Usage: exp = ReadE(scanner, prec);
* ----------------------------------
* This function reads an expression from the scanner stream,
* stopping when it encounters an operator whose precedence is
* less that or equal to prec.
*/
expressionADT ReadE(scannerADT scanner, int prec)
{
expressionADT exp, rhs;
string token;
int newPrec;
exp = ReadT(scanner, 0);
while (TRUE) {
token = ReadToken(scanner);
newPrec = Precedence(token);
if (newPrec <= prec) break;
rhs = ReadE(scanner, newPrec);
exp = NewCompoundExp(token[0], exp, rhs);
}
SaveToken(scanner, token);
return (exp);
}
/*
* Function: ReadT
* Usage: exp = ReadT(scanner);
* ----------------------------
* This function reads a single term from the scanner by matching
* the input to one of the following grammatical rules:
*
* T -> integer
* T -> identifier
* T -> ( E )
*
* In each case, the first token identifies the appropriate rule.
*/
expressionADT ReadT(scannerADT scanner, int prec)
{
expressionADT exp, rhs;
string token;
int newPrec;
exp = ReadF(scanner);
while (TRUE) {
token = ReadToken(scanner);
newPrec = Precedence(token);
if (newPrec <= prec) break;
rhs = ReadT(scanner, newPrec);
exp = NewCompoundExp(token[0], exp, rhs);
}
SaveToken(scanner, token);
return (exp);
}
int Precedence(string token)
{
if (StringLength(token) > 1) return (0);
switch (token[0]) {
case '=': return (1);
case ' ': case '-': return (2);
case '*': case '/': return (3);
default: return (0);
}
}
expressionADT ReadF(scannerADT scanner)
{
expressionADT exp;
string token;
token = ReadToken(scanner);
if (StringEqual(token, "(")) {
exp = ReadE(scanner, 0);
if (!StringEqual(ReadToken(scanner), ")")) {
Error("Unbalanced parentheses");
}
} else if (isdigit(token[0])) {
exp = NewIntegerExp(StringToInteger(token));
} else if (isalpha(token[0])) {
exp = NewIdentifierExp(token);
} else {
Error("Illegal term in expression");
}
return (exp);
}
Ответ №1:
Самый простой способ — выполнить шаг перед синтаксическим анализом, используя грамматику, которая проверяет, есть ли номер строки (т. Е. Целое число, за которым следует пробел), а затем удаляет (запоминая, что это было, чтобы вы могли сохранить это в своем массиве) и передает оставшуюся часть строки анализатору. В большинстве интерпретаторов работает более одного анализатора.