Как мне заставить мой интерпретатор BASIC на C знать, что было введено

#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:

Самый простой способ — выполнить шаг перед синтаксическим анализом, используя грамматику, которая проверяет, есть ли номер строки (т. Е. Целое число, за которым следует пробел), а затем удаляет (запоминая, что это было, чтобы вы могли сохранить это в своем массиве) и передает оставшуюся часть строки анализатору. В большинстве интерпретаторов работает более одного анализатора.