精华内容
下载资源
问答
  • 《用 C 语言开发一门编程语言 — 交互式解析器》 《用 C 语言开发一门编程语言 — 跨平台的可移植性》 《用 C 语言开发一门编程语言 — 语法解析器》 《用 C 语言开发一门编程语言 — 抽象语法树》 《用 C 语言开发...

    目录

    前文列表

    用 C 语言开发一门编程语言 — 交互式解析器
    用 C 语言开发一门编程语言 — 跨平台的可移植性
    用 C 语言开发一门编程语言 — 语法解析器
    用 C 语言开发一门编程语言 — 抽象语法树
    用 C 语言开发一门编程语言 — 异常处理
    用 C 语言开发一门编程语言 — S-表达式
    用 C 语言开发一门编程语言 — Q-表达式
    用 C 语言开发一门编程语言 — 变量元素设计
    用 C 语言开发一门编程语言 — 基于 Lambda 表达式的函数设计
    用 C 语言开发一门编程语言 — 条件分支
    用 C 语言开发一门编程语言 — 字符串与文件加载

    原生类型

    目前我们的语言只封装了 C 语言中的原生 long 和 char* 类型。对于你想要做任何更加有用的计算的情况来说,这是非常有限的。更何况,我们对这些数据类型的操作也非常有限。理想情况下,我们的语言应该封装所有原生 C 数据类型,并允许操作它们的方法。其中一个最重要的补充是允许操作十进制数。为此,您应当封装 double 类型和相关运算。而且,随着数据类型的增多,我们需要确保运算符例如 + 和 - 能够很好地在它们各自或者集合上起效。

    对于希望使用其语言中的十进制和浮点数进行计算的人来说,添加对原生类型的支持应该是相对来说比较有趣的。

    用户定义的类型

    除了添加对原生类型的支持之外,最好让用户能够添加自己的新类型,就像我们在 C 中使用结构体一样。用于执行此操作的语法或方法将取决于程序员。这是一个非常重要的部分,能使我们的语言可用于任何大小合理的项目当中去。

    这个任务对于那些对如何开发语言有特定想法的人,以及对语言本身,希望其最终设计看起来像什么的人来说,这可能会很有趣。

    [] 方括号的补充

    有些语言使用方括号 [] 表示列表。这种语法糖用于例如 list 100 (+ 10 20) 300 的情况。通过 [],你可以写成 [100 (+ 10 20) 300]。对于希望尝试添加额外语法的人来说,这应该是一个简单的补充。

    操作系统交互

    这意味着封装所有 C 的功能,例如fread,fwrite,fgetc等在 Lispy 中的等同物。这是一项相当直观的任务,但确实需要编写大量的封装函数。这就是为什么到目前为止我们还没有为我们的语言做过类似的工作。

    在类似的说明中,让我们的语言能够有权限并且适当地进行系统的调用是很好的。我们应该让它能够更改目录,列出目录中的文件以及诸如此类的功能。这是一项简单的任务,但同样需要封装大量的 C 函数。这对于任何想要将语言当作真实情况下的脚本语言来说,是极为重要的。

    希望利用他们的语言进行简单的脚本编写任务和字符串操作的人可能对实现此项目感兴趣。

    许多其他 Lisps 允许编写类似于 (def x 100) 定义值 100 到 x 上。在我们的 Lispy 中,这不会起作用,因为它会尝试计算 x 在环境中的存储为 x 的任何值。在其他 Lisps 中,这些函数称为宏,当遇到它们时,它们会停止对其参数的计算,并对它们进行未计算的操作。它们让你编写看起来像普通函数调用的东西,但实际上做的是复杂而有趣的事情。

    语言中如果有这些将会很有趣。它们使语言可以为某些工作赋予一些魔力。在许多情况下,这可以使语法更好或允许用户不需要太过于单调。

    我喜欢我们的语言在没有宏的时候,处理 def 和 if 的过程。但是如果你不喜欢它,也就是语言当前的工作方式,并希望它与传统的 Lisp 更相似,那么这可能是你有兴趣实现的东西。

    变量哈希表

    当我们查找变量名的时候,我们只是对当前环境中的所有变量进行线性搜索。我们定义的变量越多,这就变得越来越低效。

    更有效的方法是实现哈希表。此技术将变量名称转换为整数,并使用此函数将索引转换为已知大小的数组,以查找与此符号关联的值。这是编程中非常重要的数据结构,并且由于其在重负载下的出色性能而无处不在。

    任何有兴趣了解更多有关数据结构和算法的人都会很聪明地尝试实现这种数据结构或其中一种变体。

    池分配

    我们的 Lispy 很简单,但速度不快。它的性能与 Python 和 Ruby 相似。我们程序中的大多数性能开销来自这样一个问题:几乎任何过程都需要我们构造和析构 lval。因此,我们必须经常调用 malloc,这是一个很慢的函数,因为它需要操作系统为我们做一些管理。在进行计算时,会有很多 lval 类型的复制,分配和释放。

    如果我们希望减少这种开销,我们需要降低 malloc 的调用次数。执行此操作的一种方法是让在程序开始时就调用一次 malloc,分配大量内存。然后我们应该调用一些函数来替换我们所有的 malloc 调用,这些函数分割并分配这个内存以便在程序中使用。这意味着我们正在模拟操作系统的一些行为,但是只是以更快的本地方式进行。这种想法称为内存池分配,是游戏开发和其他对性能特别重视的应用程序中常用的技术。

    垃圾回收

    几乎所有其他 Lisps 实现都为我们的变量分配不同的变量。它们不会在环境中存储值的副本,而是实际上直接指向它的指针或引用。因为使用指针而不是副本,就像在 C 中一样,使用大型数据结构时所需的开销要少得多。

    如果我们存储指向值而不是副本的指针,我们需要确保在某些其他值尝试使用之前,指向的数据不会被删除。我们希望在不再引用它时删除它。执行此操作的一种方法称为 Mark 和 Sweep,用于监视环境中的值以及已分配的每个值。当一个变量被放入环境中时,它和它引用的所有内容都会被标记出来。然后,当我们希望释放内存时,我们可以迭代每个分配,并删除任何未标记的内容。

    这称为垃圾回收,是许多编程语言不可或缺的一部分。与池分配一样,实现垃圾回收器不需要很复杂,但确实需要仔细完成,实现这一点对于使这种语言适用于处理大量数据至关重要。

    尾调用优化

    我们的编程语言使用递归来进行循环。虽然这在概念上是一种非常聪明的方法,但实际上它很差。递归函数调用自身来收集计算的所有部分结果,然后才将所有结果组合在一起。当部分结果可以累积在一个循环中时,这是一种浪费的计算方法。对于旨在运行许多或无限迭代的循环而言,这尤其成问题。

    一些递归函数可以自动转换为相应的 while 循环,这些循环逐步累积总数,而不是完全累积。这种自动转换称为尾调用优化,对于使用递归进行大量循环的程序是必不可少的优化。

    词法作用域

    当我们的语言查找到未定义的变量时,它会抛出错误。如果能在评估程序之前告诉我们哪些变量未定义,那应当会更好。而且,这将让我们避免拼写错误和其他烦人的错误。在程序运行之前查找这些问题称为词法作用域,并使用变量定义的规则来尝试和推断哪些变量已定义,哪些完全没在程序中用上,从而不进行任何计算。

    静态类型

    我们程序中的每个值都要有一个相关的类型。我们在进行任何计算之前都必须确保这一点。我们的内置函数也只将某些确切的类型作为输入。我们应该能够使用此信息来推断新用户定义的函数和值的类型。在运行程序之前,我们还可以使用此信息检查是否用户使用了正确的类型调用函数。这将减少在计算之前调用具有不正确类型的函数所产生的任何错误。此检查称为静态类型。

    类型系统是计算机科学中非常有趣和基本的一部分。它们是我们在运行程序之前检测错误的最佳方法。任何对编程语言安全和类型系统感兴趣的人都会发现这个项目非常有趣。

    展开全文
  • 《用 C 语言开发一门编程语言 — 交互式 Shell》 《用 C 语言开发一门编程语言 — 跨平台》 语法解析 当我们学习一门自然语言的时候,我们往往从语法开始。当我们开发编程语言也一样,首先要考虑的就是语言的语法、...

    目录

    前文列表

    用 C 语言开发一门编程语言 — 交互式解释器l
    用 C 语言开发一门编程语言 — 跨平台的可移植性

    编程语言的本质

    在 19 世纪 50 年代,语言学家 Noam Chomsky 定义了一系列关于语言的重要理论。这些理论支撑了我们今天对于语言结构的基本理解。其中重要的一条结论就是:自然语言都是建立在递归和重复的子结构之上的。Chomsky 提出的理论是非常重要的。它意味着,虽然一门语言可以表达无限的内容,我们仍然可以使用有限的规则去解析所有用该门语言写就的东西。这些有限的规则就叫语法(grammar)。

    当我们学习一门自然语言的时候,我们往往从语法开始。当我们学习一门编程语言的时候也一样,当我们尝试开发一门编程语言的时候亦如此,首先要考虑的就是语言的语法、及其语义。

    词法分析

    大多数编程语言开发的第一步是词法分析或分词。通常使用 “Lex” 或 “Tokenizer” 来进行描述,表示将一大堆文本分解成多个符号。

    在这里插入图片描述

    词法分析器将包含源码的文件作为输入字符串,输出包含标记符号的列表。那么,在编译的后半阶段将不再参考这些字符串源代码,所以词法分析器必须产生所有后面各阶段需要的信息。之所以会有这样相对严格的格式设计,是因为这个阶段词法分析器可以做一些工作,比如移除注释或检测标识符或数字等。如果你将这些逻辑规则放在词法分析器里,那么在构造语言的其它部分时就不必再考虑这些规则了,而且你可以方便地在同一个地方集中修改这些语法规则。

    语法分析

    编译的第二阶段就是语法分析。语法分析器把标识符列表解析为一个带结点的树。用于存储这种数据的树称为 AST(抽象语法树)。

    在这里插入图片描述

    为了定义一门编程语言的语法,首先需要能够正确解析用户按照语法规则编写的程序。为此,需要编程语言程序就需要一个语法解析器,用来判断用户的输入是否合法,并产生解析后的内部表示。内部表示是一种计算机更容易理解的表示形式,有了它,我们后面的解析、求值等工作会变得更加的简单可行。

    使用 MPC 解析器组合库

    MPC(Micro Parser Combinators)是一个用于 C 的轻量且强大的解析器组合库。你可以使用这个库为任何语言编写语法解析器。编写语法解析器的方法有很多,使用解析器组合库的好处就在于,它极大地简化了原本枯燥无聊的工作,你只需要关注编写高层的抽象语法规则就可以了。

    注:MPC 的开发者就是《Build Your Own Lisp》的原作者。

    MPC 可用于:

    • 解析现有的,或开发新的编程语言
    • 解析现有的,或开发新的数据格式

    MPC 的特性:

    • 正则表达式分析器生成器
    • 语法分析器生成器
    • 易于集成到 C 语言项目(以一个源文件的形式存在)
    • 自动生成错误消息
    • Type-Generic(泛式类型)
    • Predictive, Recursive Descent

    安装

    在我们正式编写这个语法解析器之前,首先需要安装 MPC 库。MPC 库的安装非常简单,只需要将源码下载,把源文件 Copy 到我们的 C 语言项目中,然后在项目中包含 mpc 的头文件并链接 MPC 库即可。

    下载

    $ git clone https://github.com/orangeduck/mpc.git
    

    Copy

    $  ll
    总用量 140
    -rw-r--r-- 1 root root 111731 4月   7 18:12 mpc.c
    -rw-r--r-- 1 root root  11194 4月   7 18:12 mpc.h
    -rwxr-xr-x 1 root root   8632 4月   7 18:08 parsing
    -rw-r--r-- 1 root root   1203 4月   7 18:11 parsing.c
    

    引入到 parsing.c

    #include "mpc.h"
    

    编译

    gcc -std=c99 -Wall parsing.c mpc.c -lreadline -lm -o parsing
    
    • -lm:链接数学库。

    快速入门

    下面我们以编写一个 Doge(the language of Shiba Inu,柴犬语)语言的语法解析器为例,来快速熟悉 MPC 的用法。
    在这里插入图片描述

    首先解构一下 Doge 语言的语法结构:

    • Adjective(形容词):wow、many、so、such。
    • Noun(名词):lisp、language、c、book、build。
    • Phrase(短语):由 Adjective + Noun 组成。
    • Doge(柴犬语):由若干个 Phrase 组成。

    再来解释一下 Doge 语言的语法描述:

    • Phrase 由 Adjective 和 Noun 组成。
    • Doge 由任意个 Phrase 组成。

    最后,我们就可以尝试使用 MPC 来定义 Doge 语言的语法解析器了:

    • Step 1. 使用 MPC 定义 Adjective 和 Noun,为此我们创建两个解析器。其中,mpc_or 函数会返回一个解析器,该解析器表示 “取其一”,因为我们需要从 Adjective 和 Noun 中 “各取其一” 来组成 Phrase,所以分别定义了两个解析器。
    /* Build a parser 'Adjective' to recognize descriptions */
    mpc_parser_t *Adjective = mpc_or(4, 
      mpc_sym("wow"), mpc_sym("many"),
      mpc_sym("so"),  mpc_sym("such")
    );
    
    /* Build a parser 'Noun' to recognize things */
    mpc_parser_t *Noun = mpc_or(5,
      mpc_sym("lisp"), mpc_sym("language"),
      mpc_sym("book"),mpc_sym("build"), 
      mpc_sym("c")
    );
    
    • Step 2. 使用已经定义好的 Adjective 、 Noun 解析器来定义 Phrase 解析器。mpc_and 函数会返回一个解析器,该解析器只接受各 “子句” 按照顺序出现的语句。所以我们将先前定义的 Adjective 和 Noun 传递给它,表示:形容词后面紧跟着名词组成的短语。mpcf_strfold 和 free 指定了各个语句的组织(Fold)及删除(Free)方式。在 mpcf_strfold 和 free 函数的帮助下,我们不用担心什么时候加入和丢弃输入,它们将自动帮助我们完成。
    mpc_parser_t *Phrase = mpc_and(2, mpcf_strfold, Adjective, Noun, free);
    
    • Step 3. 使用 Phrase 解析器来最终定义 Doge 语言的解析器,Doge 是由若干个 Phrase 组成的,mpc_many 函数表达的正是这种逻辑关系。
    mpc_parser_t *Doge = mpc_many(mpcf_strfold, Phrase);
    

    上述语句表明 Doge 可以接受任意多条语句。这也意味着 Doge 语言是无穷的。下面列出了一些符合 Doge 语法的例子:

    /* 一条 Doge 语句由若干个 Phrase 组成,一个 Phrase 由一个 Adjective + 一个 Noun 构成。 */
    "wow book such language many lisp"  
    "so c such build such language"
    "many build wow c"
    ""
    "wow lisp wow c many language"
    "so c"
    

    通过上述步骤,我们简单的定义了一门 Doge 语言的描述自己实现了一门 Doge 语言的语法解析器。还可以继续使用 mpc 提供的其他函数,一步一步地编写能解析更加复杂的语法的解析器。

    但是很显然的,上述的代码实现方式并不友好,随着语法的复杂度的增加,代码的可读性也会越来越差。所以 mpc 还提供了一系列的函数来帮助用户更加简单地完成常见的任务,使用这些函数能够更好更快地构建复杂语言的解析器,并能够提供更加精细地控制。具体的文档说明可以参见项目主页*(https://github.com/orangeduck/mpc)*。

    下面,我们使用 MPC 提供的另一种更加简易的代码实现方式来编写 Doge 语法解析器:将整个语言的语法规则写在一个长字符串中,而不是使用啰嗦难懂的 C 语句。我们也不再需要关心如何使用 mpcf_strfold 或是 free 参数组织或删除各个语句。所有的这些工作都是都是自动完成的。

    mpc_parser_t* Adjective = mpc_new("adjective");
    mpc_parser_t* Noun      = mpc_new("noun");
    mpc_parser_t* Phrase    = mpc_new("phrase");
    mpc_parser_t* Doge      = mpc_new("doge");
    
    mpca_lang(MPCA_LANG_DEFAULT,
      "                                           \
        adjective : \"wow\" | \"many\"            \
                  |  \"so\" | \"such\";           \
        noun      : \"lisp\" | \"language\"       \
                  | \"book\" | \"build\" | \"c\"; \
        phrase    : <adjective> <noun>;           \
        doge      : <phrase>*;                    \
      ",
      Adjective, Noun, Phrase, Doge);
    
    /* Do some parsing here... */
    
    mpc_cleanup(4, Adjective, Noun, Phrase, Doge);
    
    1. 使用 mpc_new 函数定义解析器的名字。
    2. 使用 mpca_lang 函数定义这些解析器的内涵和解析器之间的逻辑关系,从而最终构成一门语言的语法规则。

    mpca_lang 函数的第一个参数是操作标记,在这里我们使用默认选项 MPCA_LANG_DEFAULT。第二个参数是 C 语言的一个长字符串。这个字符串中定义了具体的语法规则。每个规则分为两部分,用冒号 : 隔开,使用 ; 表示规则结束:

    • 冒号左边是语法规则的名字,e.g. adjective、noun、phrase、doge。
    • 右边是语法规则的定义,e.g. adjective:wow、many、so、such。

    mpca_lang 函数就是对 mpc_many、mpc_and 、 mpc_or 这些函数的封装,自动地完成这些函数的工作,让解析器定义的代码变得干净利落,不拖泥带水。

    定义语法规则的一些特殊符号的作用如下:
    在这里插入图片描述

    实现波兰表达式的语法解析

    波兰表达式

    就如我们常见的算数表达式 1+1 = 2。波兰表达式也是一种数学标记语言,它的特点是运算符会在操作数的前面。我们考虑将波兰表达式作为 Lisp 编程语言的数学运算部分。
    在这里插入图片描述
    在编写这种数据标记语言的语法规则之前,我们还是先对其进行语法解构以及语法描述:我们观察到,波兰表达式总是以操作符开头,后面跟着操作数或其他包裹在圆括号中的表达式。也就是说,波兰表达式是由:程序(Program)是由一个操作符(Operator)加上一个或多个表达式(Expression)组成的。而每个表达式又可以是一个数字或者是包裹在圆括号中的一个操作符加上一个或多个表达式。

    所以我们对波兰表达式进行了如下解构和描述:
    在这里插入图片描述

    正则表达式

    有了语法规则的描述之后,我们还需要对针对语法的输入进行约束(e.g. 如何表达开始和结束输入、如何规定可选字符和字符范围等),因为一个任意的输入中,很可能包含了一些解析器还没定义清楚的结构。我们考虑使用正则表达式(Regular Expression)来实现这一目的。

    正则表达式适合定义一些小型的语法规则,例如单词或是数字等。正则表达式不支持复杂的规则,但它清晰且精确地界定了输入是否符合规则。在 mpc 中,我们需要将正则表达式包裹在一对 / 中。例如,Number 可以用 /-?[0-9]+/ 来表示。

    在这里插入图片描述

    代码实现

    根据上面的分析,我们可以定义波兰表达式最终的语法规则:

    #include <stdio.h>
    #include <stdlib.h>
    #include "mpc.h"
    
    #ifdef _WIN32
    #include <string.h>
    
    static char buffer[2048];
    
    char *readline(char *prompt) {
        fputs(prompt, stdout);
        fgets(buffer, 2048, stdin);
    
        char *cpy = malloc(strlen(buffer) + 1);
    
        strcpy(cpy, buffer);
        cpy[strlen(cpy) - 1] = '\0';
    
        return cpy;
    }
    
    void add_history(char *unused) {}
    
    #else
    
    #ifdef __linux__
    #include <readline/readline.h>
    #include <readline/history.h>
    #endif
    
    #ifdef __MACH__
    #include <readline/readline.h>
    #endif
    
    #endif
    
    int main(int argc, char *argv[]) {
    
        /* Create Some Parsers */
        mpc_parser_t *Number   = mpc_new("number");
        mpc_parser_t *Operator = mpc_new("operator");
        mpc_parser_t *Expr     = mpc_new("expr");
        mpc_parser_t *Lispy    = mpc_new("lispy");
    
        /* Define them with the following Language */
        mpca_lang(MPCA_LANG_DEFAULT,
          "                                                     \
            number   : /-?[0-9]+/ ;                             \
            operator : '+' | '-' | '*' | '/' ;                  \
            expr     : <number> | '(' <operator> <expr>+ ')' ;  \
            lispy    : /^/ <operator> <expr>+ /$/ ;             \
          ",
          Number, Operator, Expr, Lispy);
    
        puts("Lispy Version 0.1");
        puts("Press Ctrl+c to Exit\n");
    
        while(1) {
            char *input = NULL;
    
            input = readline("lispy> ");
            add_history(input);
    
            /* Attempt to parse the user input.
             * 解析用户的每一条输入。
             * 调用了 mpc_parse 函数,并将 Lispy 解析器和用户输入 input 作为参数。
             * 它将解析的结果保存到 &r 中,如果解析成功,函数返回值为 1,失败为 0。
             */
            mpc_result_t r;
            if (mpc_parse("<stdin>", input, Lispy, &r)) {
                /* On success print and delete the AST.
                 * 解析成功时会产生一个内部结构,并保存到 r 的 output 字段中。
                 * 我们可以使用 mpc_ast_print 将这个结构打印出来,使用 mpc_ast_delete 将其删除。
                 */
                mpc_ast_print(r.output);
                mpc_ast_delete(r.output);
            } else {
                /* Otherwise print and delete the Error.
                 * 解析失败时则会将错误信息保存在 r 的 error 字段中。
                 * 我们可以使用 mpc_err_print 将这个结构打印出来,使用 mpc_err_delete 将其删除。
                 */
                mpc_err_print(r.error);
                mpc_err_delete(r.error);
            }
    
            free(input);
    
        }
    
        /* Undefine and delete our parsers */
        mpc_cleanup(4, Number, Operator, Expr, Lispy);
    
        return 0;
    }
    

    编译:

    gcc -std=c99 -Wall parsing.c mpc.c -lreadline -lm -o parsing
    

    运行,尝试解析一条波兰表达式 + 5 (* 2 2)

    $ ./parsing
    Lispy Version 0.1
    Press Ctrl+c to Exit
    
    lispy> + 5 (* 2 2)
    >
      regex
      operator|char:1:1 '+'
      expr|number|regex:1:3 '5'
      expr|>
        char:1:5 '('
        operator|char:1:6 '*'
        expr|number|regex:1:8 '2'
        expr|number|regex:1:10 '2'
        char:1:11 ')'
      regex
    lispy> hello
    <stdin>:1:1: error: expected '+', '-', '*' or '/' at 'h'
    lispy> / 1dog
    <stdin>:1:4: error: expected one of '0123456789', '-', one or more of one of '0123456789', '(', newline or end of input at 'd'
    lispy>
    <stdin>:1:1: error: expected '+', '-', '*' or '/' at end of input
    lispy> ^C
    

    可以看见,上述的正常输出就是一个 AST(Abstract Syntax Tree,抽象语法树),它用来表示用户输入的表达式的结构。操作数(Number)和操作符(Operator)等需要被处理的实际数据都位于叶子节点上。而非叶子节点上则包含了遍历和求值的信息。

    展开全文
  • 如何构建 一门 无需编译的脚本语言呢. int a =10 ; 这个怎么做呢 , 1,compare 数据类型表 int 匹配 这是整形数据类型的 2,n个空格将作为分隔符. 3, a 是个变量名 ,先缓冲着. 4, = 证明这语句是赋值语句, 5, value =...

    今天开始推理..                          --天河著 2018/10/31
    如何构建 一门 无需编译的脚本语言呢.

    int a =10 ; 
    这个怎么做呢 ,
    1,compare 数据类型表  int  匹配 这是整形数据类型的
    2,n个空格将作为分隔符.
    3, a 是个变量名 ,先缓冲着.
    4, = 证明这语句是赋值语句,
    5, value =10;

    解析
    可以把a 先存在一个类型数组,默认先2048字节数组

    Variables [] variables=new Variables[2048];
    class Variables
    {
       string 变量名;
       dataType dt;
       object value ;
    public string this[string key]
     {
      }

    解析
    int b=a+b;
    等效于   
    variables[Key] //这个key 就是分析文本的时候得到的.全部存到一个 doc.Vars 数组里.
    variables[doc.Vars] 那么就能得到对应的变量名值以及type.
    以此类推, 你也应该一个实时解释器的设计蓝图了吧.
         --天河推理~.
    然后再找一个 C# 的类库.类名,字段名,方法名,事件名,接口名,命名空间名,全部 转换成字典就好.
    或封装成所有调用和访问的代码..这可能需要很长的时间。
    然后就如反射一样。C#本来就自带反射,因此C# 开发出脚本系统是非常简单的。
    而更高级的脚本系统,完全可以使用.net 库.
    然后win32 ,nuget 那网站里也有 封装好的所有win32 ,dx api 接口.
    因此你基于 C# 之上开发的脚本语言也几乎万能.
    ==========================================
    最终或许你会思维 ,C#这么强大为啥还要重塑它自己呢.
    还不如直接C#就好.
    我说实话吧, 确实那样子,但我为啥渴望 开发一个全新的语言呢.
    其实是为了 更好地管理代码.因为我在2年不停开发C#经历里体验到.
    弱者代码碍眼,虽然还是有必要.但不善于管理查阅.
    然后有些地方希望可以 智能生成代码.通过自己的脚本.生成更加复杂或大量的有规律的C#代码.如 1000个for嵌套.
    重点是 可以按蓝图生成 类文件,接口文件,以及一大堆字段.
    如大公司一般直接通过UML架构图来生成类以及层次结构的.
    而不是逐个建立的.
    还有 未来完全可以实现人工智能写代码.弱智代码将变得毫无价值.
    必须提升高度.更加宏观的管理方式.
    而且 现在程序开发最大的问题是, 关注性能问题,关注是否并行处理数据的问题,还有大量模型未被标准化,老重复造轮子浪费大量时间。
    虽然还是有必要保留造轮子能力的编程语言,但我希望 的是
    可以简化 常见的模型,常见的使用方式。
    还有就是 有些模型会让你感觉非常难使用,因为每一句代码里面包含了大量的代码,而且模块的粒度很小,似乎是一大堆无关重要的细节耦合在一起构成的系统。
    我就是一直在思考有啥方法可以达到不琐碎却使用的是最先进的框架,自动细分粒度,控制复杂度。适应各种规模的程序开发。
    这应该是最理想的,但你学了不少企业级框架就会发现这么做细节都在黑箱子里,出了问题几乎无法解决。关于框架自动处理的细节,难以窥探,毕竟你不是框架的设计者,无法完全通晓。
    如果你通晓了,你也没必要使用它的框架了。非常矛盾。
    =================================================
    这里先不管了。好到 企业架构研究。
    我就希望 整个项目开发所需的人员配备标准化,需要多少人来支持一个中小规模的项目开发。
    然而该类型的人员该又相关的机构来培训,年审来支持。
    这是最理想的。
    然后我想到的是,未来将会又有大量类似的框架,组织来支持。甚至取代。然而还有一些保守主义支持过去的编程方式,坚持回归最原始的编程方式,而不是跟人员知识面技能相匹配组建开发组来开发。
    过去的那种开发方式 确实 根本不可能达到大型规模的。
    中等规模就需要天才来支持了。
    我的世界很理想,我也很想把现实世界理想化,标准化,简单化单一化。连C++ 都分成 VC++ ,纯C++。。你就明白根本不可能存在绝对的纯粹。。抽象理论是唯一的,却衍伸出来的实例就很多。
    全非你很多钱把大半个地球的相关企业都听你的!!
    才能实现真正的简单高抽象的编程世界,但相对来说,编程也只是普通人享受生活的一种方式而已。价值也相对降低。
    因此我没见过任何改进是绝对有益处的。
    难度高,自由度高,就形成混乱,任何人都可以学习,却并非 任何人都能达到开发大型项目的境界。

    展开全文
  • 《用 C 语言开发一门编程语言 — 交互式 Shell》 实现跨平台的可移植性 使用预处理器来解决程序跨平台的可移植性(Portability)问题。 预处理器(CPP)也是一个程序,它在真正编译程序之前运行,所以称之为预处理或...

    目录

    前文列表

    用 C 语言开发一门编程语言 — 交互式解析器l

    实现跨平台的可移植性

    理想情况下,我希望我的代码可以在任何操作系统上编译并运行,即程序的可移植性(Portability)问题。在 C 语言中,可以使用预处理器来解决这个问题。

    使用预处理器指令

    预处理器(CPP)也是一个程序,它在真正编译程序之前运行,所以称之为预处理或预编译器。预处理器的应用场景之一就是检测当前的代码在哪个操作系统中运行,从而来产生与平台相关的代码。而这也正是我们做可移植性工作时所需要的。

    这里使用预处理器指令来判断,如果程序运行在 Windows 上,则伪造一个 readline 和 add_history 函数;而在其他操作系统上运行则直接使用 GUN Readline 函数库提供的函数。

    #include <stdio.h>
    #include <stdlib.h>
    
    /*
     * 如果程序运行在 Windows 上,则伪造一个 readline 和 add_history 函数。
     */
    #ifdef _WIN32
    #include <string.h>
    
    static char buffer[2048];
    
    /* Fake readline function */
    char *readline(char *prompt) {
        fputs(prompt, stdout);
        fgets(buffer, 2048, stdin);
    
        char *cpy = malloc(strlen(buffer ) + 1);
    
        strcpy(cpy, buffer);
        cpy[strlen(cpy) - 1] = '\0';
    
        return cpy;
    }
    
    /* Fake add_history function */
    void add_history(char *unused) {}
    
    #else
    
    /*
     * 如果程序运行在 Linux 上,则直接引入 Readline 库函数。
     */
    #ifdef __linux__
    #include <readline/readline.h>
    #include <readline/history.h>
    #endif
    
    /*
     * 如果程序运行在 Linux 上,则直接引入 Readline 库函数,不需要包含 history.h 头文件。
     */
    #ifdef __MACH__
    #include <readline/readline.h>
    #endif
    
    #endif
    
    int main(int argc, char *argv[]) {
        puts("Lispy Version 0.1");
        puts("Press Ctrl+c to Exit\n");
    
        while(1) {
            char *input = NULL;
    
            input = readline("lispy> ");
            add_history(input);
    
            printf("You're a %s\n", input);
    
            free(input);
        }
        return 0;
    }
    
    展开全文
  • 如果编程语言一门武功绝学

    万次阅读 多人点赞 2021-05-22 16:30:06
    在编程的学习过程中,我们何尝不是从一招一式的函数、语法、特性等学起,掌握了一门编程语言后,再学习另一门语言就会快很多,如同拥有内功后,习得其他武功也会轻松很多。 如果编程语言是一门武功绝学,各语言分别...
  • 怎样学习一门编程语言

    万次阅读 多人点赞 2015-04-06 02:12:38
    选择一门语言确定你感兴趣的领域你可以开始学习任何编程语言(尽管其中一些被描述地比其他的更加“易学”),你得去问自己自己想用通过学习这门语言完成什么样的工作。这将会帮助你确定你应该追求的编程方式并且提供...
  • 还有一方面就是从招聘信息可以得知,现在几乎所有公司前端开发岗位都明确要求会后台语言,在实际工作中可能也要做客户端和服务器端之间的数据交互等。 所以答案是 需要 1.更有利于巩固前端知识,对网站有系统整体...
  • 作为恰饭工具里最常用的ide,如果能够做到一些自己想要的功能,那是可以极大的提高生产效(xin)率(qing)的,说不定还可以事(tou)半(tou)功(mo)倍(yu)。 萌生这个想法的初衷是因为工作当中使用了一个叫做ClearSilver的...
  • 如何学习一门新的开发语言

    千次阅读 2015-03-07 11:55:26
    作为一名软件研发,由于工作的需要,难免需要接触新的知识,新的技术,新的开发语言.有时候接触这些新的东西,不知道如何下手.每个人学习的方式都不一样,可以借鉴,不能完全照搬.最近在学习Android,我觉得可以按照...
  • 如何快速学习一门语言

    千次阅读 2014-05-11 21:44:49
    作者:colin 版权声明:自由转载-非商用-非衍生-保持署名 ...刚开始压力巨大,新项目都用脚本来开发,而且不止一门语言,这对于我这个多年来一直使用C++,Delphi等原生语言的程序员来说,感觉非常的不适应。一方面
  • 一门编程语言的通用知识点

    千次阅读 2019-07-22 11:45:18
    也就是说如果精通某一门编程语言的话,那么在学习其它门语言时就可以类比该门语言来学习,进而做到一通而百通。现在就来分析一下一门编程语言的公共知识点有哪些。 1.编程语言自身的语法规则 一门编程语言的语法...
  • 快速学习一门编程语言

    千次阅读 2015-12-11 00:26:50
    快速学习一门编程语言 流程 语法 调用 用例 流程能够把一个最简单的程序编辑, 编译, 运行起来, 强调的是掌握编程的环境和流程计算机基础知识 操作系统 计算机, 内存, 硬盘 目录, 文件 程序设计语言, 程序, 编辑, 源...
  • 如何学习一门编程语言

    千次阅读 多人点赞 2018-09-28 12:56:00
    但是最近跟同事讨论了一下到底应该如何学习一门编程语言。考虑到之前的几篇文章可能对初学者没什么帮助,而大神又不需要看。所以感觉这篇文章说一说如何学习编程语言还是挺有必要的。 首先给初学者推荐一本书:...
  • 快速深入一门语言的几个问题(Python面试题、笔试题、快速深入一门语言的绝招) 1.hello, world 目标:屏幕上打印出hello, world。 原因:不解释。 进阶:当命令行给与不同参数的时候,打印hello, 名字...
  • 如何学习一门语言

    千次阅读 2015-02-01 18:43:20
    心态这不但是学习一门新的语言最重要的,而是对任何的学习都是最重要的。下面是书中的描述,非常的精彩,特别是那个比喻: 学习一门新的语言的时候,要利用以前所学的语言的功底,但是也要保持开放的心态。有些人...
  • 受 灰太狼_cxh的文章:Android Studio 踩的坑之导入别人的 Android Studio 项目 的启发 下面我结合自己情况稍加修改,网上就只找到他这一篇是真实有用的! (注:建议去GitHub下载一些 Star 多的热门开源安卓项目...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 153,160
精华内容 61,264
关键字:

如何自己开发一门语言