parsing - 创建Brainfuck解析器,解析循环运算符的最佳方法是什么?

标签 parsing loops brainfuck

我最终创建了Brainfuck解析器(使用BASIC方言)来创建解释器,但我意识到它不像我最初想象的那样简单。我的问题是我需要一种方法来准确解析Brainfuck程序中的匹配循环运算符。这是一个示例程序:

,>,>++++++++[<------<------>>-]
<<[>[>+>+<<-]>>[<<+>>-]<<<-]
>>>++++++[<++++++++>-],<.>.

'['=循环开始

']'=循环结束

我需要记录每个匹配循环运算符的起点和终点,以便我可以根据需要在源代码周围跳转。有些循环是单独的,有些则是嵌套的。

解析此问题的最佳方法是什么?我在想,也许在源文件中移动以创建一个2D数组(或类似的记录),以记录每个匹配运算符的开始和结束位置,但这似乎在源中进行了很多“往返”操作。这是最好的方法吗?

更多信息:Brainfuck homepage

编辑:非常感谢任何语言的示例代码。

最佳答案

您是否考虑过使用堆栈数据结构来记录“跳转点”(即指令指针的位置)。

因此,基本上,每次遇到“[”时,都将指令指针的当前位置压入该堆栈。每当遇到“]”时,都将指令指针重置为堆栈顶部当前的值。循环完成后,将其弹出堆栈。

这是一个具有100个存储单元的C++示例。该代码以递归方式处理嵌套循环,尽管未进行完善,但应说明这些概念。

char cells[100] = {0};   // define 100 memory cells
char* cell = cells;      // set memory pointer to first cell
char* ip = 0;            // define variable used as "instruction pointer"

void interpret(static char* program, int* stack, int sp)
{
    int tmp;
    if(ip == 0)              // if the instruction pointer hasn't been initialized
        ip = program;        //  now would be a good time

    while(*ip)               // this runs for as long as there is valid brainF**k 'code'
    {
        if(*ip == ',')
            *cell = getch();
        else if(*ip == '.')
            putch(*cell);
        else if(*ip == '>')
            cell++;
        else if(*ip == '<')
            cell--;
        else if(*ip == '+')
            *cell = *cell + 1;
        else if(*ip == '-')
            *cell = *cell - 1;
        else if(*ip == '[')
        {           
            stack[sp+1] = ip - program;
            *ip++;
            while(*cell != 0)
            {
                interpret(program, stack, sp + 1);
            }
            tmp = sp + 1;
            while((tmp >= (sp + 1)) || *ip != ']')
            {
                *ip++;
                if(*ip == '[')
                    stack[++tmp] = ip - program;
                else if(*ip == ']')
                    tmp--;
            }           
        }
        else if(*ip == ']')
        {
            ip = program + stack[sp] + 1;
            break;
        }
        *ip++;       // advance instruction
    }
}

int _tmain(int argc, _TCHAR* argv[])
{   
    int stack[100] = {0};  // use a stack of 100 levels, modeled using a simple array
    interpret(",>,>++++++++[<------<------>>-]<<[>[>+>+<<-]>>[<<+>>-]<<<-]>>>++++++[<++++++++>-],<.>.", stack, 0);
    return 0;
}

编辑
我只是再次浏览了一下代码,我意识到while循环中存在一个错误,如果指针的值为0,它将“跳过”已解析的循环。这是我进行更改的地方:
while((tmp >= (sp + 1)) || *ip != ']')     // the bug was tmp > (sp + 1)
{
ip++;
if(*ip == '[')
    stack[++tmp] = ip - program;
else if(*ip == ']')
    tmp--;
}

以下是相同解析器的实现,但未使用递归:
char cells[100] = {0};
void interpret(static char* program)
{
    int cnt;               // cnt is a counter that is going to be used
                           //     only when parsing 0-loops
    int stack[100] = {0};  // create a stack, 100 levels deep - modeled
                           //     using a simple array - and initialized to 0
    int sp = 0;            // sp is going to be used as a 'stack pointer'
    char* ip = program;    // ip is going to be used as instruction pointer
                           //    and it is initialized at the beginning or program
    char* cell = cells;    // cell is the pointer to the 'current' memory cell
                           //      and as such, it is initialized to the first
                           //      memory cell

    while(*ip)             // as long as ip point to 'valid code' keep going
    {
        if(*ip == ',')
            *cell = getch();
        else if(*ip == '.')
            putch(*cell);
        else if(*ip == '>')
            cell++;
        else if(*ip == '<')
            cell--;
        else if(*ip == '+')
            *cell = *cell + 1;
        else if(*ip == '-')
            *cell = *cell - 1;
        else if(*ip == '[')
        {           
            if(stack[sp] != ip - program)
                stack[++sp] = ip - program;

            *ip++;

            if(*cell != 0)
                continue;
            else
            {                   
                cnt = 1;
                while((cnt > 0) || *ip != ']')
                {
                    *ip++;
                    if(*ip == '[')
                    cnt++;
                    else if(*ip == ']')
                    cnt--;
                }
                sp--;
            }
        }else if(*ip == ']')
        {               
            ip = program + stack[sp];
            continue;
        }
        *ip++;
    }
}

int _tmain(int argc, _TCHAR* argv[])
{   
    // define our program code here..
    char *prg = ",>++++++[<-------->-],[<+>-]<.";

    interpret(prg);
    return 0;
}

关于parsing - 创建Brainfuck解析器,解析循环运算符的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1055758/

相关文章:

java - 如何在 Java 源文件中获取给定行号的周围方法

解析 AMF3 对象

python - 下载 HTML5 cache.manifest 文件中列出的所有工件的最佳方式?

ascii - 脑残乘法

python-3.x - 从 Python 3 中的查询字符串中获取值,而没有 [' ' ] 显示在值中

java - 如何生成这个图案

c - 我正在使用 4 个 for 循环,2 个工作正常,其余 2 个显示问题 3,4 个循环显示无效答案

引用数据框中名称为 paste0 的列

vpn - 我如何在 BrainFuck 上打印 “What happened on the 4th of June 1989?”

interpreter - 在 Nimrod 中的 Brainfuck 翻译