“用C语言编写一个汇编程序。” 为什么要用高级语言编写用于低级语言的机器代码翻译器?


13

我的微处理器班老师给了我们一个作业,说:

“用C语言编写一个汇编程序。” -我亲爱的教授

所以对我来说似乎有点不合逻辑。

如果我没搞错,汇编语言是从机器代码到高级语言之旅的第一步。我的意思是C是比汇编语言更高级的语言。那么,用C编写汇编语言有什么意义呢?在没有C语言的情况下,他们过去在做什么?他们是用机器代码编写汇编程序吗?

对我来说,用高级语言为低级语言编写机器代码翻译器没有任何意义。

假设我们已经创建了一个全新的微处理器架构,该架构甚至没有C编译器。用C编写的汇编程序能否模拟新架构?我的意思是没用吗?

顺便说一下,我知道GNU汇编器和Netwide汇编器是用C编写的。我也想知道为什么它们是用C编写的?

最后,这是我们的教授提供给我们的简单汇编程序的示例源代码:

// to compile, gcc assembler.c -o assembler
// No error check is provided.
// Variable names cannot start with 0-9.
// hexadecimals are twos complement.
// first address of the code section is zero, data section follows the code section.
//fout tables are formed: jump table, ldi table, label table and variable table.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


//Converts a hexadecimal string to integer.
int hex2int( char* hex)  
{
    int result=0;

    while ((*hex)!='\0')
    {
        if (('0'<=(*hex))&&((*hex)<='9'))
            result = result*16 + (*hex) -'0';
        else if (('a'<=(*hex))&&((*hex)<='f'))
            result = result*16 + (*hex) -'a'+10;
        else if (('A'<=(*hex))&&((*hex)<='F'))
            result = result*16 + (*hex) -'A'+10; 
        hex++;
    }
    return(result);
}


main()
{   
    FILE *fp;
        char line[100];
        char *token = NULL;
    char *op1, *op2, *op3, *label;
    char ch;
    int  chch;

    int program[1000];
    int counter=0;  //holds the address of the machine code instruction




// A label is a symbol which mark a location in a program. In the example 
// program above, the string "lpp", "loop" and "lp1" are labels.
    struct label  
    {
        int location;
        char *label;
    };
    struct label labeltable[50]; //there can be 50 labels at most in our programs
    int nooflabels = 0; //number of labels encountered during assembly.




// Jump instructions cannot be assembled readily because we may not know the value of 
// the label when we encountered a jump instruction. This happens if the label used by
// that jump instruction appear below that jump instruction. This is the situation 
// with the label "loop" in the example program above. Hence, the location of jump 
// instructions must be stored.
    struct jumpinstruction   
    {
        int location;
        char *label;
    };
    struct jumpinstruction jumptable[100]; //There can be at most 100 jumps
    int noofjumps=0;  //number of jumps encountered during assembly.    




// The list of variables in .data section and their locations.
    struct variable
    {
        int location;
        char *name;
    };
    struct variable variabletable[50]; //There can be 50 varables at most.
    int noofvariables = 0;




//Variables and labels are used by ldi instructions.
//The memory for the variables are traditionally allocated at the end of the code section.
//Hence their addresses are not known when we assemble a ldi instruction. Also, the value of 
//a label may not be known when we encounter a ldi instruction which uses that label.
//Hence, the location of the ldi instructions must be kept, and these instructions must be 
//modified when we discover the address of the label or variable that it uses.
    struct ldiinstruction   
    {
        int location;
        char *name;
    };
    struct ldiinstruction lditable[100];
    int noofldis=0;




    fp = fopen("name_of_program","r");

    if (fp != NULL)
    {
        while(fgets(line,sizeof line,fp)!= NULL)  //skip till .code section
        {
            token=strtok(line,"\n\t\r ");
            if (strcmp(token,".code")==0 )
                break;
        } 
        while(fgets(line,sizeof line,fp)!= NULL)
        {
            token=strtok(line,"\n\t\r ");  //get the instruction mnemonic or label

//========================================   FIRST PASS  ======================================================
            while (token)
            {
                if (strcmp(token,"ldi")==0)        //---------------LDI INSTRUCTION--------------------
                {
                    op1 = strtok(NULL,"\n\t\r ");                                //get the 1st operand of ldi, which is the register that ldi loads
                    op2 = strtok(NULL,"\n\t\r ");                                //get the 2nd operand of ldi, which is the data that is to be loaded
                    program[counter]=0x1000+hex2int(op1);                        //generate the first 16-bit of the ldi instruction
                    counter++;                                                   //move to the second 16-bit of the ldi instruction
                    if ((op2[0]=='0')&&(op2[1]=='x'))                            //if the 2nd operand is twos complement hexadecimal
                        program[counter]=hex2int(op2+2)&0xffff;              //convert it to integer and form the second 16-bit 
                    else if ((  (op2[0])=='-') || ((op2[0]>='0')&&(op2[0]<='9')))       //if the 2nd operand is decimal 
                        program[counter]=atoi(op2)&0xffff;                         //convert it to integer and form the second 16-bit 
                    else                                                           //if the second operand is not decimal or hexadecimal, it is a laber or a variable.
                    {                                                               //in this case, the 2nd 16-bits of the ldi instruction cannot be generated.
                        lditable[noofldis].location = counter;                 //record the location of this 2nd 16-bit  
                        op1=(char*)malloc(sizeof(op2));                         //and the name of the label/variable that it must contain
                        strcpy(op1,op2);                                        //in the lditable array.
                        lditable[noofldis].name = op1;
                        noofldis++;                                             
                    }       
                    counter++;                                                     //skip to the next memory location 
                }                                       

                else if (strcmp(token,"ld")==0)      //------------LD INSTRUCTION---------------------         
                {
                    op1 = strtok(NULL,"\n\t\r ");                //get the 1st operand of ld, which is the destination register
                    op2 = strtok(NULL,"\n\t\r ");                //get the 2nd operand of ld, which is the source register
                    ch = (op1[0]-48)| ((op2[0]-48) << 3);        //form bits 11-0 of machine code. 48 is ASCII value of '0'
                    program[counter]=0x2000+((ch)&0x00ff);       //form the instruction and write it to memory
                    counter++;                                   //skip to the next empty location in memory
                }
                else if (strcmp(token,"st")==0) //-------------ST INSTRUCTION--------------------
                {
                    //to be added
                }
                else if (strcmp(token,"jz")==0) //------------- CONDITIONAL JUMP ------------------
                {
                    //to be added
                }
                else if (strcmp(token,"jmp")==0)  //-------------- JUMP -----------------------------
                {
                    op1 = strtok(NULL,"\n\t\r ");           //read the label
                    jumptable[noofjumps].location = counter;    //write the jz instruction's location into the jumptable 
                    op2=(char*)malloc(sizeof(op1));         //allocate space for the label                  
                    strcpy(op2,op1);                //copy the label into the allocated space
                    jumptable[noofjumps].label=op2;         //point to the label from the jumptable
                    noofjumps++;                    //skip to the next empty location in jumptable
                    program[counter]=0x5000;            //write the incomplete instruction (just opcode) to memory
                    counter++;                  //skip to the next empty location in memory.
                }               
                else if (strcmp(token,"add")==0) //----------------- ADD -------------------------------
                {
                    op1 = strtok(NULL,"\n\t\r ");    
                    op2 = strtok(NULL,"\n\t\r ");
                    op3 = strtok(NULL,"\n\t\r ");
                    chch = (op1[0]-48)| ((op2[0]-48)<<3)|((op3[0]-48)<<6);  
                    program[counter]=0x7000+((chch)&0x00ff); 
                    counter++; 
                }
                else if (strcmp(token,"sub")==0)
                {
                    //to be added
                }
                else if (strcmp(token,"and")==0)
                {
                    //to be added
                }
                else if (strcmp(token,"or")==0)
                {
                    //to be added
                }
                else if (strcmp(token,"xor")==0)
                {
                    //to be added
                }                       
                else if (strcmp(token,"not")==0)
                {
                    op1 = strtok(NULL,"\n\t\r ");
                    op2 = strtok(NULL,"\n\t\r ");
                    ch = (op1[0]-48)| ((op2[0]-48)<<3);
                    program[counter]=0x7500+((ch)&0x00ff);  
                    counter++;
                }
                else if (strcmp(token,"mov")==0)
                {
                    //to be added
                }
                else if (strcmp(token,"inc")==0)
                {
                    op1 = strtok(NULL,"\n\t\r ");
                    ch = (op1[0]-48)| ((op1[0]-48)<<3);
                    program[counter]=0x7700+((ch)&0x00ff);  
                    counter++;
                }
                else if (strcmp(token,"dec")==0)
                {
                                    //to be added
                }
                else //------WHAT IS ENCOUNTERED IS NOT AN INSTRUCTION BUT A LABEL. UPDATE THE LABEL TABLE--------
                {
                    labeltable[nooflabels].location = counter;  //buraya bir counter koy. error check
                    op1=(char*)malloc(sizeof(token));
                    strcpy(op1,token);
                    labeltable[nooflabels].label=op1;
                    nooflabels++;
                } 
                token = strtok(NULL,",\n\t\r ");  
            }
        }


//================================= SECOND PASS ==============================

                //supply the address fields of the jump and jz instructions from the 
        int i,j;         
        for (i=0; i<noofjumps;i++)                                                                   //for all jump/jz instructions
        {
            j=0;
            while ( strcmp(jumptable[i].label , labeltable[j].label) != 0 )             //if the label for this jump/jz does not match with the 
                j++;                                                                // jth label in the labeltable, check the next label..
            program[jumptable[i].location] +=(labeltable[j].location-jumptable[i].location-1)&0x0fff;       //copy the jump address into memory.
        }                                                     




                // search for the start of the .data segment
        rewind(fp);  
        while(fgets(line,sizeof line,fp)!= NULL)  //skip till .data, if no .data, also ok.
        {
            token=strtok(line,"\n\t\r ");
            if (strcmp(token,".data")==0 )
                break;

        }


                // process the .data segment and generate the variabletable[] array.
        int dataarea=0;
        while(fgets(line,sizeof line,fp)!= NULL)
        {
            token=strtok(line,"\n\t\r ");
            if (strcmp(token,".code")==0 )  //go till the .code segment
                break;
            else if (token[strlen(token)-1]==':')
            {               
                token[strlen(token)-1]='\0';  //will not cause memory leak, as we do not do malloc
                variabletable[noofvariables].location=counter+dataarea;
                op1=(char*)malloc(sizeof(token));
                strcpy(op1,token);
                variabletable[noofvariables].name=op1;
                token = strtok(NULL,",\n\t\r ");
                if (token==NULL)
                    program[counter+dataarea]=0;
                else if (strcmp(token, ".space")==0)
                {
                    token=strtok(NULL,"\n\t\r ");
                    dataarea+=atoi(token);
                }
                else if((token[0]=='0')&&(token[1]=='x')) 
                    program[counter+dataarea]=hex2int(token+2)&0xffff; 
                else if ((  (token[0])=='-') || ('0'<=(token[0])&&(token[0]<='9'))  )
                    program[counter+dataarea]=atoi(token)&0xffff;  
                noofvariables++;
                dataarea++;
            }
        }






// supply the address fields for the ldi instructions from the variable table
        for( i=0; i<noofldis;i++)
        {
            j=0;
            while ((j<noofvariables)&&( strcmp( lditable[i].name , variabletable[j].name)!=0 ))
                j++;
            if (j<noofvariables)
                program[lditable[i].location] = variabletable[j].location;              
        } 

// supply the address fields for the ldi instructions from the label table
        for( i=0; i<noofldis;i++)
        {
            j=0;
            while ((j<nooflabels)&&( strcmp( lditable[i].name , labeltable[j].label)!=0 ))
                j++;
            if (j<nooflabels){
                program[lditable[i].location] = (labeltable[j].location)&0x0fff;
                printf("%d %d %d\n", i, j, (labeltable[j].location));   
            }           
        } 

//display the resulting tables
        printf("LABEL TABLE\n");
        for (i=0;i<nooflabels;i++)
            printf("%d %s\n", labeltable[i].location, labeltable[i].label); 
        printf("\n");
        printf("JUMP TABLE\n");
        for (i=0;i<noofjumps;i++)
            printf("%d %s\n", jumptable[i].location, jumptable[i].label);   
        printf("\n");
        printf("VARIABLE TABLE\n");
        for (i=0;i<noofvariables;i++)
            printf("%d %s\n", variabletable[i].location, variabletable[i].name);    
        printf("\n");
        printf("LDI INSTRUCTIONS\n");
        for (i=0;i<noofldis;i++)
            printf("%d %s\n", lditable[i].location, lditable[i].name);  
        printf("\n");
        fclose(fp);
        fp = fopen("RAM","w");
        fprintf(fp,"v2.0 raw\n");
        for (i=0;i<counter+dataarea;i++)
            fprintf(fp,"%04x\n",program[i]);
    }   
}

2
没有隔离的设备。跨工具链非常普遍,尤其是对于小型架构。
Lars Viklund

3
“交叉”编译器/汇编器在与目标不同的系统上运行,并生成适合在目标系统上使用的工件。在远古时代,您不必在系统之间进行数据交换,但必须从头开始重新引导系统。几乎所有针对体系结构的现代开发都是在已建立的系统上完成的,将所有内容交叉编译。
Lars Viklund'7

19
您要用机器代码而不是C编写汇编程序吗?你的教授对你很好。
Winston Ewert

2
您为什么不努力在最佳的编程环境/语言中编写所有代码?汇编器也不例外。
Erik Eidt

1
在任何特定方向上都没有固定的“旅程”。
whatsisname 2016年

Answers:


17

人们用机器代码编写汇编程序。然后,他们还用汇编语言编写了代码-通常是他们自己翻译的语言的子集,因此,它们以简单的“引导程序”版本的汇编程序开始,然后根据需要为汇编程序本身添加功能。

但是,这都不是特别必要的。最后,汇编器是一个(通常是相当简单的)翻译程序。它以一种(文本)格式输入文件,然后以另一种(通常是目标文件格式)写出文件。

输入的文本以文本格式表示机器指令,而结果以二进制格式表示相同的指令,这一事实与用于实现汇编程序的语言没有多大区别-实际上,甚至比C语言更高的语言也是如此。因为SNOBOL和Python可以很好地工作-我(相当)最近在用Python编写的汇编程序上工作,并且在工作中效果很好。

就您最初如何引导事物而言:通常是在另一台具有不错的开发工具等的机器上。如果要开发新硬件,通常无论如何都要为新机器编写一个模拟器(或至少是模拟器),因此,无论如何,首先要在某些主机系统上构建和运行代码。


3
“甚至比C语言更高的语言,例如SNOBOL和Python都可以很好地工作” –这是一个很好的观点。对于NASM,我们从来没有真正考虑过比C更高的级别,但是那是在1995年,那时性能比今天重要得多,而高级语言也没有今天那么先进。这些天,肯定值得考虑替代方案。
Jules

1
自1980年代以来,我还没有听说过SNOBOL这个名字。
pacmaninbw 2016年

我曾经在Haskell中编写过一个编译器。懒惰的求值和函数链接使编写窥视孔优化器(针对生成的机器代码)变得异常简单。
托尔比约恩Ravn的安徒生

10

您看到的连接不存在。

与其他任何编程任务一样,“编写汇编程序”是一个编程任务。您使用最适合该任务的工具来处理该任务。编写汇编程序没有什么特别的。根本没有理由不使用高级语言编写它。C实际上是一个很低的级别,我可能更喜欢C ++或其他更高级别的语言。

汇编语言实际上完全不适合这样的任务。合理使用汇编语言的情况非常少见。仅当您需要做无法用高级语言表达的事情时。


1
其他答案很好,但是我发现这是最简单的答案,尤其是前两个句子。阅读问题时,我对自己说的是同一件事。
MetalMikester,2016年

如今,只有特定于硬件的黑客才需要手动编写汇编语言。例如,在某些CPU上设置保护模式需要特定的指令序列,而逻辑上等效的序列还不够好。几乎所有普通程序都不需要任何特定的指令序列来执行所需的任务,因此,没有理由要求任何特定的序列,而只是逻辑上等效的一组指令。优化编译器可以完全相同地提高执行性能(指令计数,挂钟时间,代码缓存大小)。
Mikko Rantalainen

9

在没有C语言的情况下,他们过去在做什么?他们是用机器代码编写汇编程序吗?

汇编本质上是机器代码的助记符。机器语言中的每个操作码都有一个汇编助记符,即x86中的NOP为0x90。这使得汇编程序相当简单(nb大多数汇编程序都有两次遍历,一个遍历进行翻译,第二遍进行生成/解析地址/引用。)第一个汇编程序是手工编写的,并手工翻译(可能在纸上)为机器代码。更好的版本是用手工“汇编”汇编器编写和汇编的,新功能是通过这种方式添加的。可以通过这种方式构建新语言的编译器。过去,编译器通常会输出汇编,并在其后端使用汇编器!

对我来说,用高级语言为低级语言编写机器代码翻译器没有任何意义。... [现有的汇编程序]用C编写。我也想知道为什么用C编写?

  • 用高级语言编写更复杂的软件通常比较容易。
  • 通常,与上级语言相比,使用下级语言来跟踪您的工作通常需要更多的代码和更多的精力。
    • 一行C可以翻译成很多指令。在C ++(或C)中进行简单分配通常会生成至少3条汇编指令(加载,修改,存储;),可能需要20条或更多条指令(可能是数百条)才能完成更高级别的单行指令语言(例如c ++或c)。人们通常希望将时间花在解决问题上,而不是花时间弄清楚如何在机器代码中实现解决方案。

尽管自托管是一种编程语言的共同里程碑/理想功能,但汇编的级别如此之低,以至于大多数程序员都希望在更高级别上工作。即没有人愿意在汇编中(或其他任何东西)编写汇编器

假设我们已经创建了一个全新的微处理器架构,该架构甚至没有C编译器。

引导程序是在新架构上获取工具链的过程。

基本过程是:

  • 编写一个新的后端,该后端了解如何为新的CPU(或MCU)生成代码
  • 编译并测试您的后端
  • 使用新的后端交叉编译所需的编译器(和os等)
  • 将这些二进制文件转移到新系统

您不必一次用汇编语言(新的或旧的)编写代码,而是应该选择最佳的语言来编写汇编器/后端/代码生成器。

用C编写的汇编程序能否模拟新架构?

汇编器不模拟!

如果使用新的(或现有的)机器语言开发新的CPU,则通常需要模拟器来进行测试;即通过模拟器运行随机指令和数据,并将输出与原型CPU上的相同指令和数据进行比较。然后找到错误,修复错误,然后重复。


3

用C(或任何其他高级语言)编写汇编程序的原因包括,所有可能用来证明用该高级语言编写任何其他程序的理由。在这种情况下,最主要的可能是可移植性和可用性。

可移植性:如果您用母语编写汇编程序,则该平台上将具有汇编程序。如果用C编写,则在任何具有C编译器的平台上都有一个汇编器。例如,这使您可以在工作站上为嵌入式平台编译代码并移动二进制文件,而无需直接在目标设备上完成所有操作。

可用性:对于大多数人而言,使用高级语言编写的程序比使用汇编语言或(较差的)原始机器代码编写的程序更容易阅读,推理和修改程序。因此,使用高级语言开发和维护汇编程序更加容易,因为您可以根据高级语言提供给您的抽象来思考,而不用考虑使用低级语言负责的细节。


3

仅专门解决问题的这一部分:

“通过这种方式,我知道GNU汇编器和Netwide汇编器是用C编写的。我也想知道为什么它们是用C编写的?”

作为最初编写Netwide Assembler的团队的一部分,这个决定对我们来说似乎很明显,以至于我们基本上没有考虑任何其他选择,但是如果这样做,我们将基于以下结论得出相同的结论:原因如下:

  • 用较低级别的语言来编写它会更困难,而且更耗时。
  • 用高级语言编写它可能会更快,但是出于性能方面的考虑(特别是用作汇编器后端的汇编器,为了避免使编译器减慢的速度,它必须非常快。最终会处理大量代码,这是我们特别希望允许的用例),而且我不相信主要作者有任何更高级别的通用语言(这是在Java流行之前,因此,这样的语言当时还很零散。我们确实将perl用于某些元编程任务(以有用的格式为代码生成器后端生成指令表),但是它实际上并不适合整个程序。
  • 我们想要操作系统的可移植性
  • 我们希望硬件平台具有可移植性(用于生产交叉编译器)

这使决定变得很容易:当时符合ANSI标准的C(如今又称为C89)是唯一真正达到所有这些要求的语言。如果当时有一个标准化的C ++,那么我们可能已经考虑过了,但是那时不同系统之间对C ++的支持还很少,所以编写可移植的C ++有点噩梦。


1

一件事与另一件事绝对无关。Web浏览器是否严格使用html或php或其他某种Web内容语言编写?不,为什么会这样?汽车只能由其他汽车驾驶而不由人驾驶吗?

将一个二进制位(某些ascii)转换为另一二进制位(某些机器代码)只是一项编程任务,用于此任务的编程语言是您想要的任何一种。您可以并且已经用许多不同的语言编写了汇编程序。

新语言最初不能以自己的语言编写,因为还没有针对它们的编译器/汇编器。如果没有针对新语言的编译器,则必须用其他某种语言编写第一个,然后您最终进行引导,即使这对于引导也很有意义。(html和网络浏览器,一个需要花一些时间才能吐出一些东西的程序,永远不会用html编写)。

不一定要是新语言,也可以是现有语言。新的C或C ++编译器不会立即自动编译自己。

对于汇编语言和C,几乎所有新的或修改的指令集的前两种语言。我们不是过去,而是现在。我们可以很容易地用C或Java或python或任何我们想要的指令集和汇编语言生成汇编器,即使它尚不存在。同样,有许多可重定位的C编译器,即使汇编器尚不存在,我们也可以为所需的任何汇编语言输出汇编语言。

这正是我们使用新指令集所做的。取一些未在其新指令集上运行且其C编译器未针对我们的新指令集或其汇编程序进行编译的计算机,创建交叉汇编器和交叉编译器。在创建和仿真逻辑时开发并使用它。经过正常的开发周期来发现错误,并修复错误并再次测试,直到理想情况下所有工具和逻辑都准备就绪为止。并且根据目标,例如它是一个无法运行操作系统的微控制器,您将永远没有理由进行引导,以使工具链使用本机指令集生成并运行。您将始终交叉编译。除了在Wayback机器中以外,用汇编器编写汇编器从来没有任何意义。

是的,如果您可以回去或假装回去,那么第一个组装工是一个拿着铅笔和纸的人,他写了一些对他们来说有意义的东西,然后在旁边写了一些对逻辑有意义的东西。然后使用开关或其他方式将位插入机器(google pdp8或pdp11或altair 8800)并使其起作用。最初没有计算机模拟器,您只需要通过盯着逻辑足够长的时间或旋转芯片的若干转速来弄清逻辑。今天的工具已经足够好,您可以获得A0的成功,因为它不仅是一个大电阻,而且很多它都可以工作,您可能仍需要旋转才能完全模拟不了的东西,但是您现在通常可以在第一spi,而不必等待第三或第四旋转,

如您所愿,在您的Wayback机器中,您将手工汇编的代码带入其中,并用它说从磁带或卡中加载程序。您还可以用机器代码手动编写汇编程序,可能不是一个完整的汇编程序,而是使编程容易一些的程序。然后,使用该工具创建一个可以处理更高级或更复杂的语言(宏汇编程序)的工具,然后使用该工具创建更复杂的语言,最终得到FORTRAN或BASIC或B或其他任何东西。然后,您开始考虑使用相同的语言进行引导,将交叉编译器重新编写为本地编译器。当然,理想情况下,您为此需要某种环境或操作系统。

当我们创建或测试硅时,我们可以/确实需要盯着一个为零的信号。这些工具默认情况下会向我们显示二进制或十六进制,并且某些工具甚至可以进行查找,以便这些工具显示一些助记符(也许是汇编代码),但工程师(硅/硬件和软件)通常可以读取足够的内容。机器代码,或使用反汇编/清单“查看”说明。

根据您的操作,您可能只是将一些机器代码放入测试向量中,而不是重新编写,重新编译或重新组装测试。例如,如果您具有流水线并在某个深度进行预取,则可能需要或想要在程序末尾填充一些nop或其他实际指令,以使该流水线不会对未定义的指令进行呕吐,您可以选择仅在最低级别的列表/文件中填充机器代码,而不要尝试让编译器或汇编器或链接器执行此操作。

当然,在测试处理器时,您确实需要处理未定义的内容,也许不需要关心位等。因此,您需要进入机器代码,并在正常工作的程序中修改指令中的一个或多个特定位。值得编写一个程序来执行此操作还是仅手动执行。同样,在测试ECC时,您想要翻转一个或多个位,并查看它们是否被纠正或捕获。当然,编写程序可以轻松得多,也可以手动完成。

当然,有些语言不会产生在处理器,早期pascal,java,python等上运行的代码。您需要使用其他某种语言编写的VM才能使用这些语言。您不能使用Java编译器来制作Java虚拟机,基于语言的设计没有任何意义。

(是的,在这些语言的纯实现之后,可以肯定的是,最终有人会构建一个不纯的后端,该后端有时可以针对实际的指令集而不是vm指令集,然后在这种情况下,您可以使用该语言自行编译它或vm,如果您确实感到需要,例如gcc的gnu java前端)。

随着时间的流逝,也许我们仍然可能不会使用C语言编写C编译器。我们使用诸如bison / flex之类的东西来编写其他我们不想自己编写的C语言。C语言中有一定百分比,但其他语言中则有一些百分比,该语言使用其他一些编译器来输入位并输出其他位。有时,这种方法也用于生成汇编程序。取决于编译器/汇编器的设计者(具有输入位然后输出其他位的任务的程序)如何实现它。程序生成的解析器可以手动编程,这很耗时,因此人们需要寻找快捷方式。就像您可以在汇编器中编写汇编器一样,但是人们在寻找捷径。

Web浏览器只是一个程序,它需要一些位并吐出一些其他位。汇编程序只是一个程序,它吸收一些位并吐出一些其他位。编译器只是一个程序,它吸收一些位并吐出其他一些位。等等。对于所有这些,每个编程任务的输入位和输出位都有一套记录的规则。这些任务和位足够通用,可以使用任何可用的编程语言(能够执行位/字节操作并处理输入和输出)。此处的密钥可用。从零开始获取本书并尝试使用linux。尝试使用带有模拟前面板的pdp8或pdp11或altair 8800或其他模拟器。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.