JavaScript를 사용하여 컴파일러 및 가상 머신 만들기

16840 단어 compilernodejavascript
https://github.com/EliteDaMyth/JS-VM-Compiler-환매

JavaScript로 컴파일러와 가상 머신을 만들어 보도록 하겠습니다.


이것은 자바스크립트의 Brainf*ck 언어에 사용되는 가상 컴퓨터와 컴파일러의 매우 간단하고 간단한 구현이다.
이 프로젝트의 목적은 모든 컴파일러와 가상 기기가 반드시 복잡하고 방대해야 하는 것은 아니라는 것을 모두에게 알리는 것이다.이 글을 다 읽은 후에, 너는 기계와 언어가 어떻게 작동하는지 이해할 수 있기를 바란다.
만약 당신이 무엇을 배웠거나, 이것이 당신에게 도움이 된다고 생각한다면, 별 하나를 남기는 것을 잊지 마세요!모든 관계자들의 참가를 환영합니다.

  • Let's Make a Compiler and Virtual Machine in JavaScript
  • What is a compiler?
  • Lexical Analysis

  • Parsing
  • Abstract Syntax Tree

  • Compiling/Interpreting
  • Bytecode
  • What exactly is a Virtual Machine?
  • How to run the code?
  • Contact me.
  • 컴파일러란?


    만약 누군가가 당신에게 컴파일러의 이름을 묻는다면, GCC, Rust 컴파일러, CLANG 컴파일러 등 컴파일러를 생각할 수 있습니다. 우리는 단어 컴파일러와 프로그램을 연결해서 이 프로그램은 코드를 받고 실행 가능한 파일을 출력합니다.
    그러나 컴파일러는 다양한 모양과 크기를 가지고 프로그래밍 언어뿐만 아니라 정규 표현식, 데이터베이스 조회, 심지어 HTML 템플릿까지 다양한 것을 컴파일할 수 있다.나는 네가 매일 한두 개의 컴파일러를 사용할 것이며 심지어는 이 점을 의식하지 못할 것이라고 확신한다.컴파일러 자체의 정의가 실제적으로 매우 느슨하고 사람들의 예상을 훨씬 뛰어넘기 때문이다.위키피디아의 정의는 다음과 같습니다.

    A compiler is computer software that transforms computer code written in one programming language (the source language) into another computer language (the target language). Compilers are a type of translator that support digital devices, primarily computers. The name compiler is primarily used for programs that translate source code from a high-level programming language to a lower level language (e.g., assembly language, object code, or machine code) to create an executable program.


    컴파일러는 통역사다.이것은 매우 모호하다.실행 가능한 파일을 만들기 위한 고급 언어를 번역하는 컴파일러는 특수한 형식의 컴파일러일 뿐입니다.컴파일러 크기의 차이가 매우 클 수 있습니다.컴파일러는 GNU 컴파일러 집합 (GCC) 에 1500만 줄이 넘는 코드가 있는 것처럼 수백 줄이나 수백만 줄의 코드로 작성할 수 있다.우리는 틀림없이 그렇게 큰 물건을 만들지 않을 것이다. 그렇다면 우리는 도대체 무엇을 만들고 있는 것일까?AST를 입력으로 하고 VM에서 실행할 바이트 코드를 출력하는 간단한 컴파일러를 만들 것입니다.지금, 아스트가 뭐예요?AST를 이해하려면 프로그래밍 언어가 어떻게 작동하는지 알아야 한다.
    각 언어에는
  • 어휘 분석/표기화
  • 해석
  • 어셈블리/평가
  • 어휘 분석


    첫 번째 단계는 화려하게 들리지만 기본적으로 코드가'기호화폐'로 변하고 있다.예를 들어, Brainf*ck 태그 관리자에서는 프로그램의 문자열을 입력으로 하고 태그 배열을 반환합니다.즉, .+.<>-을 입력하면 비슷한
    ['.', '+', '.', '<', '>', '-']
    
    모든 영패가 사실상 하나의 대상인 것을 제외하고는 일부 실용 프로그램을 가지고 있다.( See tokenizer.js )
    이것은 중요한 절차이다. 왜냐하면 우리는 프로그램에서 식별되지 않은 문자를 발견했는지, 그리고 전진하기 전에 가능한 한 빨리 오류를 던졌는지 알 수 있기 때문이다.그것은 또한 해상도로 하여금 프로그램을 더욱 쉽게 읽게 한다.

    해석


    위키백과에 따르면:

    Parser is a software component that takes input data (frequently text) and builds a data structure – often some kind of parse tree, abstract syntax tree, or other hierarchical structure – giving a structural representation of the input, checking for correct syntax in the process. [...] The parser is often preceded by a separate lexical analyzer, which creates tokens from the sequence of input characters;


    간단하게 말하면 해석기는 입력을 입력을 나타내는 데이터 구조로 전환한다.
    만약 이전에 자바스크립트를 사용한 적이 있다면, 아마도 JSON.parse()을 사용한 적이 있을 것입니다.그것의 작업 원리는 기본적으로 같다.문자열을 입력으로 하고 Javascript 객체로 해석합니다.유일한 차이점은, 우리의 해석기에서, 우리는 영패의 대상을 가져와 추상적인 문법 트리로 전환할 것이다.

    추상 구문 트리


    지금, 당신은 AST가 무엇인지 알고 싶을 것이다.대부분의 해석기와 컴파일러에서 원본 코드 내부에 표시되는 데이터 구조를'문법 트리'또는'추상적 문법 트리'(약칭AST)라고 부른다.'요약' 은 원본 코드에서 볼 수 있는 일부 세부 사항이 AST에서 생략되었다는 사실에 기초를 두고 있다.분호, 줄 바꾸기, 빈칸, 주석, 대괄호, 네모난 괄호, 원괄호 - 언어와 해석기에 따라 이런 세부 사항은AST에 표시되지 않고, 단지 구축할 때 해석기를 지도할 뿐이다.
    우리의 사례에서 우리의AST는 다음과 같은 구조를 가지고 있다.
    AstNode {
      _valid_names_list: [
        'MoveLeft',
        'MoveRight',
        'Increment',
        'Decrement',
        'Output',
        'Input',
        'While'
      ],
      _name: 'Increment',
      _next: AstNode { // This is the Next Item in the AST
        _valid_names_list: [
          'MoveLeft',
          'MoveRight',
          'Increment',
          'Decrement',
          'Output',
          'Input',
          'While'
        ],
        _name: 'Increment',
        _next: AstNode {
          _valid_names_list: [Array],
          _name: 'Increment',
          _next: [AstNode] // This will keep going on until the end of the program.
        }
      }
    }
    
    대상 속성 _next은AST의 다음 블록입니다.Lexer에 100개의 영패가 있다면 AST의 깊이는 100이 된다는 뜻이다.마지막 노드의 _next 속성은 null이 됩니다.

    번역


    이것은 모든 프로그래밍 언어의 세 번째 부분이자 마지막 부분이다.앞에서 읽은 바와 같이 컴파일러는 기본적으로 번역기이다.우리의 예에서, 우리는 컴파일러가 AST를 입력으로 하고, VM이 실행할 수 있도록 바이트 코드를 출력하기를 희망한다.

    바이트 코드


    바이트 코드도 이식 가능한 코드라고 하는데 기본적으로 기계의 명령어이다.해석기는 바이트 코드가 유효하다는 것을 설명한다.바이트 코드의 모든 명령은 하나의 조작 코드와 선택할 수 있는 조작 수로 구성되어 있다.조작 코드의 폭은 1바이트로 명령의 첫 번째 바이트이다.
    바이트 코드 명령은 다음과 같습니다.
    {"op": "<>","value": x} // move memory pointer to += x (x can be negative)
    {"op": "+-","value": x} // update current byte to += x (x can be negative)
    {"op": "PRINT","value": x} // print current byte
    {"op": "READ","value": x} // read a value to current byte
    {"op":"ifjump", index: x} // set memory pointer to x, if current byte is zero
    {"op":"jump", index: x} // set memory pointer to x (unconditional goto)
    
    예를 들어, 우리는 .--<>[.], 우리의 바이트 코드를 가지고 있다
    CompiledProgram {
      _byte_code: [
        { op: 'PRINT' },
        { op: '+-', value: -1 },
        { op: '+-', value: -1 },
        { op: '<>', value: -1 },
        { op: '<>', value: 1 },
        { op: 'ifjump', index: 9 },
        { op: 'PRINT' },
        { op: 'jump', index: 6 }
      ]
    }
    
    이제 우리는 바이트 코드가 무엇인지 알고 VM이 무엇인지 알 수 있다.

    VM이란 무엇입니까?


    가상 머신이라는 단어를 읽을 때 가장 먼저 떠오르는 것은 VMWARE나 VirtualBox 같은 것이다.그러나 이것은 우리가 구축하고자 하는 그런 가상 기기가 아니다.
    우리가 구축하고자 하는 것은 프로그래밍 언어를 실현하는 가상 컴퓨터이다.때로는 몇 개의 함수만 포함하고, 때로는 몇 개의 모듈을 구성하며, 때로는 클래스와 대상의 집합이기도 하다.그것들의 형상을 확정하기는 매우 어렵다.그러나 이것은 중요하지 않다.중요한 것은 기존의 기계를 모방하지 않는다는 것이다.그것들은 기계다.
    가상 기기를 이해하기 위해서 우리는 진정한 기계가 어떻게 작동하는지 이해해야 한다.
    네가 일상생활에서 만나는 거의 모든 기계는 Von Neumann architecture에 기초를 두고 있다.
    펑 노이먼의 모델에서 컴퓨터는 두 가지 핵심 부분이 있는데 하나는 처리 단원이고 하나는 산술 논리 단원(ALU)과 여러 개의 프로세서 레지스터를 포함한다. 하나는 제어 단원이고 하나는 명령 레지스터와 프로그램 계수기를 포함한다.그것들은 함께 중앙 프로세서라고 불리며, 통상적으로 CPU라고 약칭한다.이 밖에도 컴퓨터에는 메모리(RAM), 대용량 메모리(하드디스크 드라이브를 생각하면)와 입력/출력 장치(키보드와 모니터)가 포함되어 있다.
    다음은 펑 노이만 건축의 초도이다.

    컴퓨터가 켜져 있으면 CPU:
  • 메모리에서 명령을 받습니다.프로그램 카운터는 CPU가 메모리에서 다음 명령을 찾을 수 있는 위치를 알려 줍니다.
  • 에서 명령을 디코딩합니다.수행할 작업을 결정합니다.
  • 은 이 명령을 집행한다.이것은 레지스터의 내용을 수정하거나 레지스터에서 메모리로 데이터를 전송하거나 메모리에서 데이터를 이동하거나 출력을 생성하거나 입력을 읽는 것을 의미할 수 있다.
  • 이 세 단계는 기한 없이 중복된다.이른바 취득-디코딩-집행주기다.지령 주기.이것이 바로 컴퓨터의 시계다.
    이제 우리는 진정한 컴퓨터가 어떻게 작동하는지 조금 알게 되면 가상 컴퓨터를 이해할 수 있다.
    정의에 따라

    A virtual machine is a computer built with software. It’s a software entity that mimics how a computer works.


    진정한 컴퓨터와 마찬가지로 우리의 가상 컴퓨터도 디코딩-실행 순환을 얻는다.우리의 가상 기기에도 프로그램 카운터가 하나 있는데, 그것은 또 하나의 창고, 메모리, 바늘 등이 있는데, 이 모든 것은 소프트웨어로 만든 것이다.
    저는 여기서 코드를 상세하게 소개하지 않을 것입니다. 당신은 vm.js file에서 자신을 찾을 수 있습니다.그러나 기본적으로, 우리 가상 기기는 컴파일러로부터 바이트 코드를 출력하고, 명령마다 반복하며, 바이트 명령에 따라 메모리 위치를 바꾸고, PRINT 바이트 명령을 읽을 때 현재 메모리 위치에서 문자열을 출력하는 것을 하고 있다.

    코드를 어떻게 실행합니까?


    노드를 제외하고 코드는 어떠한 의존항도 필요 없다.js가 실행을 시작합니다.다음 명령을 사용하여 코드를 실행합니다.
    > git pull https://github.com/EliteDaMyth/JS-VM-Compiler.git
    > node testing.js
    

    연락해.


    언제든지 EliteDa 신화 #0690을 통해 연락 주세요.일부 잘못된 컨텐트가 발견되면 이 저장소에 문제를 만들 수도 있습니다.내 디스코트 서버에 가입하고 싶으면 https://discord.gg/ZbQBRZ5Jnc을 찾을 수 있습니다

    좋은 웹페이지 즐겨찾기