Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parsing 创建Brainfuck解析器,解析循环运算符的最佳方法是什么?_Parsing_Loops_Brainfuck - Fatal编程技术网

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

Parsing 创建Brainfuck解析器,解析循环运算符的最佳方法是什么?,parsing,loops,brainfuck,Parsing,Loops,Brainfuck,我正在创建一个Brainfuck解析器(用一种基本的方言)来最终创建一个解释器,但我意识到这并不像我最初想的那么简单。我的问题是,我需要一种在Brainfuck程序中准确解析匹配循环运算符的方法。这是一个示例程序: ,>,>++++++++[<------<------>>-] <<[>[>+>+<<-]>>[<<+>>-]<<<-] >>>+++

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

,>,>++++++++[<------<------>>-]
<<[>[>+>+<<-]>>[<<+>>-]<<<-]
>>>++++++[<++++++++>-],<.>.
,>,>++++++++[-]
+>+[-]++++++[-],.
“[”=循环的开始

']'=循环结束

我需要记录每个匹配循环操作符的起点和终点,以便根据需要跳过源。有些循环是单独的,有些是嵌套的

解析这个的最佳方法是什么?我在想,也许可以在源文件中创建一个2D数组(或类似的数组),记录每个匹配操作符的开始和结束位置,但这看起来像是在源文件中来回移动。这是最好的方法吗

更多信息:


编辑:非常欣赏任何语言的示例代码。

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

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

这里是一个C++的例子,里面有100个存储单元。代码以递归方式处理嵌套循环,虽然没有细化,但应该说明这些概念

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;
}
下面是同一解析器的实现,但不使用递归:

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;
}
char单元格[100]={0};
无效解释(静态字符*程序)
{
int cnt;//cnt是将要使用的计数器
//仅在分析0-1循环时
int stack[100]={0};//创建一个堆栈,100层深-建模
//使用简单数组-并初始化为0
int sp=0;//sp将用作“堆栈指针”
char*ip=program;//ip将用作指令指针
//它在程序的开始或结束时初始化
char*cell=cells;//cell是指向“当前”内存单元的指针
//因此,它被初始化为第一个
//存储单元
while(*ip)//只要ip指向“有效代码”,则继续运行
{
如果(*ip==',')
*cell=getch();
否则,如果(*ip=='。)
putch(*单元);
否则,如果(*ip=='>'))
cell++;

否则,如果(*ip=='每次找到“[”,请在堆栈上推送当前位置(或另一个“标记”标记或“上下文”)。当您越过“]”时,您处于循环的末尾,可以从堆栈中弹出标记标记


因为在BF中,“[”已经检查了一个条件,可能需要跳过“]”,所以您可能需要一个标志,指示在当前循环上下文中跳过指令。

我没有示例代码,但是

我可能会尝试使用堆栈,并使用如下算法:

  • (执行指令流)
  • 遭遇[
  • 如果指针==0,则继续读取,直到遇到“]”,并且在找到它之前不要执行任何指令。转到步骤1
  • 如果指针!=0,则将该位置推到堆栈上
  • 继续执行指令
  • 如果您遇到一个问题]
  • 如果指针==0,则从堆栈中弹出[并继续(转到步骤1)
  • 如果指针!=0,查看堆栈顶部,然后转到该位置。(转到步骤5)

  • 其他海报描述的Python 3.0堆栈算法示例:

    program = """ 
    ,>,>++++++++[<------<------>>-]
    <<[>[>+>+<<-]>>[<<+>>-]<<<-]
    >>>++++++[<++++++++>-],<.>.
    """
    
    def matching_brackets(program):
        stack = []
    
        for p, c in enumerate(program, start=1):
            if c == '[':
                stack.append(p)
            elif c == ']':
                yield (stack.pop(), p)
    
    print(list(matching_brackets(''.join(program.split()))))
    
    program=”“”
    ,>,>++++++++[-]
    +>+[-]++++++[-],.
    """
    def匹配_括号(程序):
    堆栈=[]
    对于枚举中的p,c(程序,开始=1):
    如果c=='[':
    stack.append(p)
    elif c==']':
    产量(stack.pop(),p)
    打印(列表(匹配的括号(“”.join(program.split()))
    

    (老实说,这只找到匹配的括号。我不知道brainf*ck,所以我不知道下一步该怎么做。)

    很有趣,就在几天前,我正在用Java编写一个brainf*ck解释器

    我遇到的一个问题是,当时对命令的解释不够充分,没有提到关于嵌套循环的部分

    基本上,为了总结这个问题,官方页面说,当指令是
    [
    且当前内存位置是
    0
    ,然后跳转到下一个
    ]
    。正确的行为是跳转到相应的
    ]
    ,而不是下一个

    实现此行为的一种方法是跟踪嵌套级别。我通过使用一个跟踪嵌套级别的计数器来实现这一点

    以下是解释器主循环的一部分:

    do {
      if (inst[pc] == '>') { ... }
      else if (inst[pc] == '<') { ... }
      else if (inst[pc] == '+') { ... }
      else if (inst[pc] == '-') { ... }
      else if (inst[pc] == '.') { ... }
      else if (inst[pc] == ',') { ... }
      else if (inst[pc] == '[') {
        if (memory[p] == 0) {
          int nesting = 0;
    
          while (true) {
            ++pc;
    
            if (inst[pc] == '[') {
              ++nesting;
              continue;
            } else if (nesting > 0 && inst[pc] == ']') {
              --nesting;
              continue;
            } else if (inst[pc] == ']' && nesting == 0) {
              break;
            }
          }
        }
      }
      else if (inst[pc] == ']') {
        if (memory[p] != 0) {
          int nesting = 0;
    
          while (true) {
            --pc;
    
            if (inst[pc] == ']') {
              ++nesting;
              continue;
            } else if (nesting > 0 && inst[pc] == '[') {
              --nesting;
              continue;
            } else if (inst[pc] == '[' && nesting == 0) {
              break;
            }
          }
        }
      }
    } while (++pc < inst.length);
    
    do{
    如果(inst[pc]=='>'){…}
    
    否则,(VB.NET)[PC]==`p>,这里是我在C++中作为例子给出的相同的代码,但是移植到了加里。我决定把它贴在这里,因为加里提到他试图用基本的方言编写他的解析器。
    Public cells(100) As Byte
    
    Sub interpret(ByVal prog As String)
        Dim program() As Char
    
        program = prog.ToCharArray()  ' convert the input program into a Char array
    
        Dim cnt As Integer = 0        ' a counter to be used when skipping over 0-loops                                      
        Dim stack(100) As Integer     ' a simple array to be used as stack
        Dim sp As Integer = 0         ' stack pointer (current stack level)
        Dim ip As Integer = 0         ' Instruction pointer (index of current instruction)
        Dim cell As Integer = 0       ' index of current memory
    
        While (ip < program.Length)   ' loop over the program
            If (program(ip) = ",") Then
                cells(cell) = CByte(AscW(Console.ReadKey().KeyChar))
            ElseIf (program(ip) = ".") Then
                Console.Write("{0}", Chr(cells(cell)))
            ElseIf (program(ip) = ">") Then
                cell = cell + 1
            ElseIf (program(ip) = "<") Then
                cell = cell - 1
            ElseIf (program(ip) = "+") Then
                cells(cell) = cells(cell) + 1
            ElseIf (program(ip) = "-") Then
                cells(cell) = cells(cell) - 1
            ElseIf (program(ip) = "[") Then
                If (stack(sp) <> ip) Then
                    sp = sp + 1
                    stack(sp) = ip
                End If
    
                ip = ip + 1
    
                If (cells(cell) <> 0) Then
                    Continue While
                Else
                    cnt = 1
                    While ((cnt > 0) Or (program(ip) <> "]"))
                        ip = ip + 1
                        If (program(ip) = "[") Then
                            cnt = cnt + 1
                        ElseIf (program(ip) = "]") Then
                            cnt = cnt - 1
                        End If
                    End While
                    sp = sp - 1
                End If
            ElseIf (program(ip) = "]") Then
                ip = stack(sp)
                Continue While
            End If
            ip = ip + 1
        End While
    End Sub
    
    Sub Main()
        ' invoke the interpreter
        interpret(",>++++++[<-------->-],[<+>-]<.")
    End Sub
    
    公共单元(100)作为字节
    子解释(ByVal prog作为字符串)
    Dim program()作为字符
    program=prog.tocharray()'将输入程序转换为字符数组
    Dim cnt As Integer=0'跳过0个循环时使用的计数器
    Dim stack(100)As Integer'用作堆栈的简单数组
    Dim sp As Integer=0'堆栈指针(当前堆栈级别)
    Dim ip作为整数=0'指令指针(当前指令的索引)
    将单元格设置为整数=当前内存的0'索引
    而(ipPublic cells(100) As Byte
    
    Sub interpret(ByVal prog As String)
        Dim program() As Char
    
        program = prog.ToCharArray()  ' convert the input program into a Char array
    
        Dim cnt As Integer = 0        ' a counter to be used when skipping over 0-loops                                      
        Dim stack(100) As Integer     ' a simple array to be used as stack
        Dim sp As Integer = 0         ' stack pointer (current stack level)
        Dim ip As Integer = 0         ' Instruction pointer (index of current instruction)
        Dim cell As Integer = 0       ' index of current memory
    
        While (ip < program.Length)   ' loop over the program
            If (program(ip) = ",") Then
                cells(cell) = CByte(AscW(Console.ReadKey().KeyChar))
            ElseIf (program(ip) = ".") Then
                Console.Write("{0}", Chr(cells(cell)))
            ElseIf (program(ip) = ">") Then
                cell = cell + 1
            ElseIf (program(ip) = "<") Then
                cell = cell - 1
            ElseIf (program(ip) = "+") Then
                cells(cell) = cells(cell) + 1
            ElseIf (program(ip) = "-") Then
                cells(cell) = cells(cell) - 1
            ElseIf (program(ip) = "[") Then
                If (stack(sp) <> ip) Then
                    sp = sp + 1
                    stack(sp) = ip
                End If
    
                ip = ip + 1
    
                If (cells(cell) <> 0) Then
                    Continue While
                Else
                    cnt = 1
                    While ((cnt > 0) Or (program(ip) <> "]"))
                        ip = ip + 1
                        If (program(ip) = "[") Then
                            cnt = cnt + 1
                        ElseIf (program(ip) = "]") Then
                            cnt = cnt - 1
                        End If
                    End While
                    sp = sp - 1
                End If
            ElseIf (program(ip) = "]") Then
                ip = stack(sp)
                Continue While
            End If
            ip = ip + 1
        End While
    End Sub
    
    Sub Main()
        ' invoke the interpreter
        interpret(",>++++++[<-------->-],[<+>-]<.")
    End Sub
    
    #include <stdio.h>
    
    char *S[9999], P[9999], T[9999],
        **s=S, *p=P, *t=T, c, x;
    
    int main() {
        fread(p, 1, 9999, stdin);
        for (; c=*p; ++p) {
            if (c == ']') {
                if (!x)
                    if (*t) p = *(s-1);
                    else --s;
                else --x;
            } else if (!x) {
                if (c == '[')
                    if (*t) *(s++) = p;
                    else ++x;
                }
    
                if (c == '<') t--;
                if (c == '>') t++;
                if (c == '+') ++*t;
                if (c == '-') --*t;
                if (c == ',') *t = getchar();
                if (c == '.') putchar(*t);
            }
        }
    }
    
    #include <assert.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <sys/mman.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    void error(char *msg) {
        fprintf(stderr, "Error: %s\n", msg);
    }
    
    enum { MEMSIZE = 30000 };
    
    char *mem;
    char *ptr;
    char *prog;
    size_t progsize;
    
    int init(char *progname) {
        int f,r;
        struct stat fs;
        ptr = mem = calloc(MEMSIZE, 1);
        f = open(progname, O_RDONLY);
        assert(f != -1);
        r = fstat(f, &fs);
        assert(r == 0);
        prog = mmap(NULL, progsize = fs.st_size, PROT_READ, MAP_PRIVATE, f, 0);
        assert(prog != NULL);
        return 0;
    }
    
    int findmatch(int ip, char src){
        char *p="[]";
        int dir[]= { 1, -1 };
        int i;
        int defer;
        i = strchr(p,src)-p;
        ip+=dir[i];
        for (defer=dir[i]; defer!=0; ip+=dir[i]) {
            if (ip<0||ip>=progsize) error("mismatch");
            char *q = strchr(p,prog[ip]);
            if (q) {
                int j = q-p;
                defer+=dir[j];
            }
        }
        return ip;
    }
    
    int run() {
        int ip;
        for(ip = 0; ip>=0 && ip<progsize; ip++)
            switch(prog[ip]){
            case '>': ++ptr; break;
            case '<': --ptr; break;
            case '+': ++*ptr; break;
            case '-': --*ptr; break;
            case '.': putchar(*ptr); break;
            case ',': *ptr=getchar(); break;
            case '[': /*while(*ptr){*/
                      if (!*ptr) ip=findmatch(ip,'[');
                      break;
            case ']': /*}*/
                      if (*ptr) ip=findmatch(ip,']');
                      break;
            }
    
        return 0;
    }
    
    int cleanup() {
        free(mem);
        ptr = NULL;
        return 0;
    }
    
    int main(int argc, char *argv[]) {
        init(argc > 1? argv[1]: NULL);
        run();
        cleanup();
        return 0;
    }
    
    package interpreter;
    
    import java.awt.event.ActionListener;
    
    import javax.swing.JTextPane;
    
    public class Brainfuck {
    
        final int tapeSize = 0xFFFF;
        int tapePointer = 0;
        int[] tape = new int[tapeSize];
        int inputCounter = 0;
    
        ActionListener onUpdateTape;
    
        public Brainfuck(byte[] input, String code, boolean debugger,
                JTextPane output, ActionListener onUpdate) {
            onUpdateTape = onUpdate;
            if (debugger) {
                debuggerBF(input, code, output);
            } else {
                cleanBF(input, code, output);
            }
        }
    
        private void debuggerBF(byte[] input, String code, JTextPane output) {
            for (int i = 0; i < code.length(); i++) {
                onUpdateTape.actionPerformed(null);
                switch (code.charAt(i)) {
                case '+': {
                    tape[tapePointer]++;
                    break;
                }
                case '-': {
                    tape[tapePointer]--;
                    break;
                }
                case '<': {
                    tapePointer--;
                    break;
                }
                case '>': {
                    tapePointer++;
                    break;
                }
                case '[': {
                    if (tape[tapePointer] == 0) {
                        int nesting = 0;
    
                        while (true) {
                            ++i;
    
                            if (code.charAt(i) == '[') {
                                ++nesting;
                                continue;
                            } else if (nesting > 0 && code.charAt(i) == ']') {
                                --nesting;
                                continue;
                            } else if (code.charAt(i) == ']' && nesting == 0) {
                                break;
                            }
                        }
                    }
                    break;
                }
                case ']': {
                    if (tape[tapePointer] != 0) {
                        int nesting = 0;
    
                        while (true) {
                            --i;
    
                            if (code.charAt(i) == ']') {
                                ++nesting;
                                continue;
                            } else if (nesting > 0 && code.charAt(i) == '[') {
                                --nesting;
                                continue;
                            } else if (code.charAt(i) == '[' && nesting == 0) {
                                break;
                            }
                        }
                    }
                    break;
                }
                case '.': {
                    output.setText(output.getText() + (char) (tape[tapePointer]));
                    break;
                }
                case ',': {
                    tape[tapePointer] = input[inputCounter];
                    inputCounter++;
                    break;
                }
                }
            }
        }
    
        private void cleanBF(byte[] input, String code, JTextPane output) {
            for (int i = 0; i < code.length(); i++) {
                onUpdateTape.actionPerformed(null);
                switch (code.charAt(i)) {
                case '+':{
                    tape[tapePointer]++;
                    break;
                }
                case '-':{
                    tape[tapePointer]--;
                    break;
                }
                case '<':{
                    tapePointer--;
                    break;
                }
                case '>':{
                    tapePointer++;
                    break;
                }
                case '[': {
                    if (tape[tapePointer] == 0) {
                        int nesting = 0;
    
                        while (true) {
                            ++i;
    
                            if (code.charAt(i) == '[') {
                                ++nesting;
                                continue;
                            } else if (nesting > 0 && code.charAt(i) == ']') {
                                --nesting;
                                continue;
                            } else if (code.charAt(i) == ']' && nesting == 0) {
                                break;
                            }
                        }
                    }
                    break;
                }
                case ']': {
                    if (tape[tapePointer] != 0) {
                        int nesting = 0;
    
                        while (true) {
                            --i;
    
                            if (code.charAt(i) == ']') {
                                ++nesting;
                                continue;
                            } else if (nesting > 0 && code.charAt(i) == '[') {
                                --nesting;
                                continue;
                            } else if (code.charAt(i) == '[' && nesting == 0) {
                                break;
                            }
                        }
                    }
                    break;
                }
                case '.':{
                    output.setText(output.getText()+(char)(tape[tapePointer]));
                    break;
                }
                case ',':{
                    tape[tapePointer] = input[inputCounter];
                    inputCounter++;
                    break;
                }
                }
            }
        }
    
        public int[] getTape() {
            return tape;
        }
    
        public void setTape(int[] tape) {
            this.tape = tape;
        }
    
        public void editTapeValue(int counter, int value) {
            this.tape[counter] = value;
        }
    
    }
    
    case '[': {
        if (tape[tapePointer] == 0) {
            int nesting = 0;
    
            while (true) {
                ++i;
    
                if (code.charAt(i) == '[') {
                    ++nesting;
                    continue;
                }
                else if (nesting > 0 && code.charAt(i) == ']') {
                    --nesting;
                    continue;
                }
                else if (code.charAt(i) == ']' && nesting == 0) {
                    break;
                }
            }
        }
        break;
    }
    case ']': {
        if (tape[tapePointer] != 0) {
            int nesting = 0;
    
            while (true) {
                --i;
    
                if (code.charAt(i) == ']') {
                    ++nesting;
                    continue;
                }
                else if (nesting > 0 && code.charAt(i) == '[') {
                    --nesting;
                    continue;
                }
                else if (code.charAt(i) == '[' && nesting == 0) {
                    break;
                }
            }
        }
        break;
    }