向 C 程序员介绍无代码编程技术 (PWCT)






4.62/5 (9投票s)
通过 PWCT 可视化编程语言使用 C 编程语言。
引言
十年前,当我开始开发编程无代码技术(PWCT)软件时,我热衷于创建一个可视化编程语言。与许多面向初学者或仅限于特定领域的视觉编程工具不同,这个工具是为专家程序员创建的。但是,专家程序员为什么要在打字而不是直接使用自己喜欢的编程语言(如 C 和 C++)直接输入基于文本的源代码时,还要关心使用可视化语言进行编程呢?!
这一切都与将编程原理应用于编写代码本身的过程有关。是的,我们多年来一直这样做是错误的,但我们如何才能在理论和实践层面注意到这一点并证明这一点呢。
本文将为 C 程序员提供可视化编程的概念,解释为什么您不应该再直接编写 C 代码,为什么代码必须为您生成,为什么您应该拥有程序的视觉表示,为什么您应该与视觉表示进行交互,并能够使用可视化编程来创建新代码,而无需直接输入该代码。
我们是程序员,我们每天都在做什么?我们正在编写代码?当然,但我们的目标不是编写代码,这只是我们用来实现目标的手段。我们存在于这个世界上是为了解决问题,通过开发新软件让世界变得更美好,我们创造的软件越具创新性和实用性,世界就越美好。当我们知道如何利用技术解决问题时,我们就不能容忍问题,非程序员可能接受的无计划工作、重复和随机任务等,程序员不能接受。因为我们是机器的主人,我们知道如何控制它,避免一遍又一遍地做同样的事情,并以高水平的准确性获得非常快速的结果。因此,我始终鼓励所有计算机用户至少了解编程的基础知识,但这篇帖子不是关于向非程序员介绍编程,而是关于向专家 C 程序员介绍可视化编程,这些专家程序员是许多有用且强大的软件(如操作系统、编译器、虚拟机、游戏引擎、数据库管理系统、网络协议、驱动程序等)背后的真正程序员。
那么,让我们从头开始吧,您还记得您进入编程世界的第一天吗?是的,我是指那个有趣且著名的程序,它会在屏幕上打印“hello world
”消息。
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("Hello world\n");
return 0;
}
当然,我们可以写得更短,我们可以将 int
改为 void
并删除 return
语句,我们还可以删除函数参数。
编写这个简单代码有什么问题?
问题是,当我想要在屏幕上显示一条消息(目标)时,我使用了以下步骤
- 使用头文件
- 编写 main 函数
- 使用大括号 {} 来确定函数的开始和结束
- 使用
printf
函数打印消息 - 使用分号 ; 来结束语句
太多工作可以用一行代码替代。
在批处理文件中,它是
echo Hello world
在 Python 中
print "Hello world"
在 Ruby 中
puts "Hello world"
在 Clipper/Harbour/Visual FoxPro 中
? "Hello world"
现在我们遇到了另一个问题,太多编程语言了,顺便说一句,其中大多数都是用 C 实现的,那么为什么 C 程序员要创建新的编程语言呢?他们是 C 语言的专家,他们了解这门语言,他们知道如何用它来创建稳定高效的软件。当然,新语言并非为了解决这个小问题而生,每种编程语言都有其故事,编程范式或特定技术的兴起。C++ 开始为 C 添加面向对象编程范式,然后随着时间的推移又添加了许多其他功能。Java 以其可移植性而闻名,并使用虚拟机在不重新编译的情况下跨不同平台执行相同的程序,其虚拟机提供了可移植性和安全性,这对于互联网应用程序很重要。现在 Java 在 Android 应用程序开发中发挥着至关重要的作用。像 Cobol、Clipper、Visual Foxpro、Harbour 等语言是为了使业务应用程序的开发变得简单快捷的任务而开发的。像 Ruby 这样的语言旨在以智能的方式融合不同的编程范式,拥有提供面向对象编程、函数式编程和元编程的动态语言,这极大地有助于开发像 Ruby on Rails (ROR) 这样成功的 Web 框架,它使用 MVC 设计模式并应用“不要重复自己”和“约定优于配置”等良好原则。Python 是一种非常成功的脚本语言,它弥合了简单脚本语言和 C 等强大语言之间的差距,使用 C 扩展 Python 非常容易,并且我们可以以多种方式使用 Python,例如桌面和 Web 开发,当我们需要 C & C++ 应用程序中没有的、由 Lua 这样快速小巧的语言提供的更多功能时,它还可以嵌入到 C & C++ 应用程序中。
我为什么要讲这些故事?因为这是与编程语言和编写代码相关的主要问题之一。不同编程语言提供的扩展和自定义级别对每个人来说都不够,这促使程序员创建新的编程语言,而不是使用一种语言。
一种新语言并不能解决问题,它只是在一段时间内解决了某些问题的一种权宜之计,一旦技术发展,就会出现许多新问题,为创建另一种新语言打开大门!
现在,让我们总结一下我们遇到的一些问题
- 冗余(例如 ; , {} , 使用 break,还有很多!)
- 扩展级别不够(非 100% 自然,这导致了新语言的产生)
- 自定义级别非常低(更改语言的语法 = 创建新语言!)
- 要使用一种语言,您需要知道其语法(不难,但有时可能会出现语法错误)
- 编写更多代码来表达自己 = 降低生产力
- 可读性与可写性之间的冲突
- 更改语言 = 学习曲线 + 更多成本
当我们解决所有这些问题时会发生什么?不再有冗余,我们可以获得高度的扩展性和自定义性,现在您可以摆脱语言语法的束缚,并能够更改它并使用您喜欢的单词(比使用预处理器更好)进行工作,而不会影响同一项目中其他程序员在程序的同一部分上工作,其中每个程序员都能以自己的语言看到相同的代码。如何将当前编程语言视为可以更改而无需更改程序的平台?如何在使用自然语言阅读程序的同时,使用另一种非冗长的语言编写程序。
所有这些都是我们可以通过编程无代码技术(PWCT)做到的,自 2013 年以来,我一直支持 C 编程语言,以便能够使用 PWCT 创建更强大的软件。
背景
我假设您是一位 C 程序员,并花了一些时间观看以下视频,以了解 PWCT 环境的外观 在此处。
Using the Code
当我开始学习编程时,我先读了一些书,然后大部分时间我通过实践示例和项目来学习。之后,我开始重新阅读同一本书,才发现我错过了很多有用的信息,但也学到了更多!随着时间的推移,我从书籍、开源项目以及自己解决新问题的过程中学到了很多东西!
我学到的最重要的事情之一是“阅读时要有耐心,要相信作者,忘掉你知道如何做事,也许你会从中获得一些新想法,有些想法可以改变世界,把想法当作一个孩子,它会随着时间而成长壮大”。
在本节中,我们将通过在 C 语言之上使用 PWCT 创建真实项目来看到一些示例。
目标:我想创建一个新的动态编程语言(编译器、虚拟机、标准库等),它提供比我已知的语言更好的灵活性。我需要在面向对象编程之上使用声明式编程,并使用嵌套结构,这样我就可以为客户端代码创建特定领域的语言,同时仍然拥有用于面向对象设计的类。与 Ruby 做类似的事情不同,但它是通过使用函数式编程、代码块和元编程来实现的,我的新语言将呈现出不同且新颖的东西,看起来像 QML (Qt) 和 REBOL,但方式不同,它赋予我更大的能力来快速表达问题解决方案。
- 阶段 (1):为字符串和列表创建一些 ADT
- 阶段 (2):为编译器创建扫描器、解析器和代码生成阶段
- 阶段 (3):创建虚拟机来执行代码并进行优化
- 阶段 (4):为常用任务创建标准库
- 阶段 (5):在开发 Web 应用程序中测试该语言
我将在语言发布给公众用户后,稍后更详细地讨论这种新语言。
现在,我将向您展示一些在 PWCT 中设计该语言的片段,PWCT 会为我们生成 C 代码!
示例:我需要一个快速的函数来从链表中获取列表项。
在 C 中处理链表时,我可以使用数据结构本身,或者使用隐藏实现细节的函数。我决定使用函数进行抽象(客户端代码不直接与数据结构交互,并且尽量减少使用预处理器,我只在真正必要时使用它)。
下图展示了 List
结构。
我们有指向第一个和最后一个元素的指针(pFirst
和 pLast
),并且每个元素都有指向下一个和上一个元素的指针。
我们将列表的大小存储在 int 类型的 nSize
变量中(我目标是至少 32 位系统)。
列表结构包含一个指向用户最后访问的元素的指针,以及该元素之后的下一个元素的编号(这是列表用于快速获取元素的缓存)。
下图展示了 get item 函数的高层视图。
该函数获取列表指针和要查找的项目索引,并返回项目指针。
注意:搜索使用的是项目索引(而不是项目值)。
欢迎来到编程无代码技术世界!它看起来像代码,但它是一个具有有用颜色和相关数据录入表单的树。您在这个世界中所做的一切都与您的基于文本的代码隔离。在这里,您是在 GUI 世界中编程,而不是仅仅在一个增强了语法着色、代码折叠和智能感知的基于文本的代码编辑器中。
Visual Studio、Code-Blocks、Qt Creator、Sublime、Notepad++ 或任何文本编辑器都可以为您提供很大帮助,但代码仍然是基于文本的,您很容易出现语法错误,您无法控制语言的语法,不创建新语言就无法更改它,或者至少会给在同一项目中工作的其他程序员带来问题。
让我们看看导航功能,开始看看我们感兴趣的内容。
例如,我们可以打开声明的变量
pItem
的初始值为 NULL
,函数在成功或失败时返回 pItem
。
一开始,函数可以快速获取第一个或最后一个元素,然后更新缓存。
第一个元素的指针存储在 pList
->pFirst
->pValue
中,而最后一个元素的指针存储在 pList
->pLast
->pValue
中。
pFirst
和 pLast
的类型是 Items *
,而 pValue
就像 pItem
一样,类型是 Item *
。
在第一种情况下,当 index == 1
时,我们可以直接设置 pList
->nNextItemAfterLastAccess = 2
,而不是使用表达式 index + 1
。
函数直接返回结果,而不是设置 pItem
值并在函数末尾使用一个 return 语句。
List
缓存是内联更新的,没有使用一个获取列表指针和项目指针来更新缓存并增加 nNextItemAfterLastAccess
的函数。
我们可以做很多更改或改进,但现在请专注于导航功能。
我们有一组步骤被打包在一个注释“快速获取第一个或最后一个元素”下。
稍后这有助于理解函数的各个部分或对一组步骤执行操作,例如(剪切、复制、粘贴、删除等)。
现在,我们可以看到函数定义
从上面的表单,我们可以确定函数名和参数。
我们可以输入返回值的类型,或者从静态列表中选择。
您会看到一个名为“仅原型”(Prototype only)的复选框。选中它,我们将获得函数原型而不是函数体,用于头文件。
当我们手动编写内容时,我们具有 intellisense/autocomplete 功能,可以显示变量、结构中的项和嵌套结构、函数名等。
现在,我们已经看到了一个实际示例,展示了如何使用可视化组件来表示我们的程序,而不是基于文本的源代码。您会注意到我对语言的外观做了一些小的更改,但生成的代码看起来就像手动编写的代码一样。
您对将生成的内容拥有完全的控制权。
注意:此函数可以进行优化和重写,使其风格更好。例如,线性搜索不需要从第一个元素到最后一个元素开始,因为这种情况不会发生(线性搜索找到第一个或最后一个元素),因为在前面的步骤中我们直接获取了第一个/最后一个元素。
该函数通过项目索引获取项目,当它使用 if ( x == index ) 找到项目时,我没有使用 break 语句,因为一旦我们找到项目,for 循环就不会继续。
该列表和该函数的实际用途出现在您想要用列表和嵌套列表以及动态成员替换静态成员的结构的使用时。
Item * ring_list_getitem ( List *pList,int index )
{
int x ;
Items *pItems ;
Item *pItem ;
pItem = NULL ;
assert(pList != NULL);
if ( index > 0 && ( ring_list_getsize(pList) > 0 )
&& index <= ring_list_getsize(pList) ) {
/* Quickly Get The First or The Last Item */
if ( index == 1 ) {
pList->pLastItemLastAccess = pList->pFirst ;
pList->nNextItemAfterLastAccess = index + 1 ;
return pList->pFirst->pValue ;
}
else if ( index == ring_list_getsize(pList) ) {
pList->pLastItemLastAccess = pList->pLast ;
pList->nNextItemAfterLastAccess = index + 1 ;
return pList->pLast->pValue ;
}
/* Quickly get the next item */
else if ( ( index == pList->nNextItemAfterLastAccess )
&& ( pList->pLastItemLastAccess != NULL ) ) {
pList->pLastItemLastAccess = pList->pLastItemLastAccess->pNext ;
pList->nNextItemAfterLastAccess++ ;
return pList->pLastItemLastAccess->pValue ;
}
/* Quickly get the current item */
else if ( index == pList->nNextItemAfterLastAccess - 1 ) {
return pList->pLastItemLastAccess->pValue ;
}
/* Quickly get item after the current item */
else if ( ( index > pList->nNextItemAfterLastAccess )
&& ( pList->pLastItemLastAccess != NULL ) ) {
pItems = pList->pLastItemLastAccess ;
for ( x = pList->nNextItemAfterLastAccess - 1 ; x <= index ; x++ ) {
if ( x == index ) {
pList->nNextItemAfterLastAccess = index+1 ;
pList->pLastItemLastAccess = pItems ;
}
pItem = pItems->pValue ;
pItems = pItems->pNext ;
}
return pItem ;
}
/* Quickly get item before the current item */
else if ( ( ( pList->nNextItemAfterLastAccess - index ) < index )
&& ( pList->pLastItemLastAccess != NULL ) ) {
pItems = pList->pLastItemLastAccess ;
for ( x = pList->nNextItemAfterLastAccess - 1 ; x >= index ; x-- ) {
if ( x == index ) {
pList->nNextItemAfterLastAccess = index+1 ;
pList->pLastItemLastAccess = pItems ;
}
pItem = pItems->pValue ;
pItems = pItems->pPrev ;
}
return pItem ;
}
/* Linear Search From Start */
pItems = pList->pFirst ;
for ( x = 1 ; x <= index ; x++ ) {
if ( x == index ) {
pList->nNextItemAfterLastAccess = index + 1 ;
pList->pLastItemLastAccess = pItems ;
}
pItem = pItems->pValue
pItems = pItems->pNext ;
}
}
return pItem ;
}
关注点
您可以更改任何组件(生成的步骤和生成的源代码),您可以更改组件名称、数据录入表单。PWCT 非常开放,可以在极短的时间内进行任何此类更改。
此链接 提供了解释这一切的教程。
历史
我从 2005 年 12 月开始开发 PWCT,该工具支持多种语言,如 Harbour、Python 和 C。
我的大多数应用程序都基于 HarbourPWCT,在过去的两年里,我开始花大部分时间使用 CPWCT。