Ring 编程语言






4.72/5 (27投票s)
一款免费开源、创新实用的通用多范式脚本语言,使用 C/C++ 开发
引言
我一直对编程语言的设计和实现感兴趣,而 Ring 编程语言(一款于 2016 年 1 月 25 日发布的通用多范式语言)是我在这个领域的第三个项目,此前还有“无代码编程技术”(2005-2015)和“Supernova 编程语言”(2009-2010)。
在本文中,我将尝试介绍这门语言,它为何被设计出来!以及您可以使用它做什么。
从一开始,请记住这是一个开源项目,您可以免费获取、使用和修改(MIT 许可证)。如果您想贡献或获取源代码,请查看 项目源代码(GitHub)和 语言网站,以获取更多资源,如(文档和 支持论坛)。
此外,您还可以下载 适用于 Windows 的 Ring 1.0(二进制发行版) 或 适用于 Ubuntu Linux 的 Ring 1.0(32 位二进制发行版)。
我们还有 适用于 Mac OS X 的 Ring 1.0(二进制发行版) 和 使用 Qt 进行移动应用开发的 Ring 1.0
背景
2011 年 11 月,我开始考虑从头开始创建新版本的 “无代码编程技术”(PWCT)软件。我一直致力于为该软件创建跨平台版本,并增加对 Web 和移动开发的支持。PWCT 的大部分源代码是用 VFP(Microsoft Visual FoxPro 9.0 SP2)编写的,该软件附带一个简单的脚本语言来创建组件,称为(RPWI)。该软件包含支持生成 Harbour、C、Supernova 和 Python 等编程语言代码的组件。
我一直在寻找一种编程语言,可以用来构建开发环境,提供跨平台支持,更高的生产力,更好的性能,可用于组件脚本编写,并且可以用于开发不同类型的应用程序。我决定不使用多种编程语言,而是使用一种编程语言来创建开发环境、组件脚本和应用程序。
我考察了许多编程语言,如 C、C++、Java、C#、Lua、PHP、Python 和 Ruby。我避免直接使用 C 或 C++,因为我需要的生产力水平要高于这些语言提供的水平,而且一个对初学者或专业人士友好的可视化编程环境背后的语言必须易于使用且富有成效。出于某些原因,我也避免使用 Java 和 C#!我想使用一种动态编程语言,而这些语言是静态类型的。Java 是跨平台的,C# 也是通过 Mono 实现的,但使用大量的类以及强制使用面向对象,使用冗长的语言对我来说并不合适。我需要一种小巧但快速且富有成效的语言,同时我需要更好地控制垃圾收集器(GC),我需要一个为快速应用程序设计的更好的 GC。
Lua 小巧且快速,但被排除了,因为我需要一种功能更强大的语言来处理大型应用程序。PHP 是一种 Web 编程语言,其语法与 C 非常相似,这导致它不够通用,也不够简单,无法满足我的需求。Python 和 Ruby 更接近我的需求,但我需要一些更简单、更小巧、更快、更富有成效的语言。Python 和 Ruby 是区分大小写的,列表索引从 0 开始计数,您必须在调用函数之前定义它,Ruby 的面向对象和消息传递的使用超出了我的需求,并降低了性能,Python 的语法(缩进、使用 self、:、pass 和 _)不符合我的目标。
所有这些语言都是成功的语言,在各自的领域都做得很好,但我需要一种不同的语言,它带来了新的想法和智能的实现(创新、就绪、简单、小巧、灵活和快速)。
Ring 是一种创新且实用的通用多范式脚本语言,可以嵌入到 C/C++ 项目中,可以使用 C/C++ 代码进行扩展,以及/或作为独立语言使用。支持的编程范式包括命令式、过程式、面向对象、函数式、元编程、使用嵌套结构的声明式编程以及自然编程。该语言是可移植的(Windows、Linux、Mac OS X、Android 等),可用于创建控制台、GUI、Web、游戏和移动应用程序。该语言的设计理念是简单、小巧、灵活和快速。它是一种动态语言(动态类型和弱类型),将源代码编译为字节码,然后由 Ring 虚拟机执行,Ring 虚拟机与 Ring 编译器集成在一个程序中。该语言的第一个版本(约 100,000 行 C/C++/Ring 代码)于 2016 年 1 月 25 日发布。
为什么选择 Ring?
该语言简单,力求自然,鼓励组织,并提供了透明和可视化的实现。它具有紧凑的语法和一组功能,使程序员能够在极短的时间内创建自然接口和声明式领域特定语言。它非常小巧、快速,并配有智能垃圾收集器,使内存处于程序员的控制之下。它支持多种编程范式,并配有实用且有用的库。该语言旨在提高生产力并开发可扩展的高质量解决方案。
该语言的设计有一个明确的目标
- 应用程序编程语言
- 提高生产力并开发可扩展的高质量解决方案
- 小巧快速的语言,可嵌入 C/C++ 项目
- 简单易学的语言,可用于教育和介绍编译器/虚拟机概念
- 通用语言,可用于创建领域特定的库、框架和工具
- 实用语言,旨在创建下一版“无代码编程技术”软件
Using the Code
我准备了 10 个示例来介绍,您可以使用 Ring 网站提供的在线版本运行所有这些示例。
当然,我将从“Hello World”程序开始!
See "Hello, World!"
Ring 使用 (See
) 和 (Give
) 来打印输出和获取用户输入。
该语言使用特殊的关键字(与其他语言不同)。这些特殊词被选为(小巧且易于书写,同时含义清晰)。无论如何,如果您打算将该语言添加到您的项目中,您可以修改源代码并更改任何内容!
从一开始,这就表明 Ring 不是任何其他语言的克隆,但它确实借鉴了一些其他语言的理念,如 C、C++、C#、Java、PHP、Python、Ruby、Lua、Basic、Supernova 和 Harbour。此外,该语言还带来了新的理念,特别是关于抽象和创建自然声明式接口,可作为领域特定语言使用。此外,该语言的实现(透明且可视化)有助于在编译器课程中使用它。作为一个快速的多范式语言,并使用 ANSI C 编写,它也为将该语言嵌入 C/C++ 项目提供了很好的机会。
该语言不区分大小写,您可以写 "SEE
"、"see
" 或 "See
"。
主函数是可选的,将在语句执行完毕后执行,并且对于使用局部作用域很有用。
Ring 使用动态类型和词法作用域。变量名前不需要加 '$
'!
您可以使用 '+
' 运算符进行字符串连接,并且该语言是弱类型的,会根据上下文自动在数字和字符串之间进行转换。
列表索引从 1
开始。您可以在定义之前调用函数。赋值运算符使用深拷贝(在此操作中没有引用)。您可以按值传递数字和字符串,但按引用传递列表和对象。
for-in 循环可以更新列表项。我们可以在定义时使用列表,如下面的示例所示。
aList = [ [1,2,3,4,5] , aList[1] , aList[1] ]
see aList # print 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
我们可以轻松地跳出多个循环。
for x = 1 to 10
for y = 1 to 10
see "x=" + x + " y=" + y + nl
if x = 3 and y = 5
exit 2 # exit from 2 loops
ok
next
next
该语言鼓励组织,告别那些混乱的日子,在那些语言中,程序员从函数开始,然后是类,然后又是函数,各种东西混杂在一起!每个源文件都遵循以下结构
- 加载文件
- 语句和全局变量
- 函数
- 包和类
这使我们能够使用包、类和函数,而无需使用关键字来结束这些组件。
我们可以写单行注释和多行注释
注释以 #
或 //
开头。
多行注释写在 /*
和 */
之间。
Ring 提供了透明的实现。我们可以了解编译器每个阶段正在发生的事情以及虚拟机在运行时正在进行的操作。例如:ring helloworld.ring -tokens -rules -ic
==================================================================
Tokens - Generated by the Scanner
==================================================================
Keyword : SEE
Literal : Hello, World!
EndLine
==================================================================
==================================================================
Grammar Rules Used by The Parser
==================================================================
Rule : Program --> {Statement}
Line 1
Rule : Factor --> Literal
Rule : Range --> Factor
Rule : Term --> Range
Rule : Arithmetic --> Term
Rule : BitShift --> Arithmetic
Rule : BitAnd --> BitShift
Rule : BitOrXOR --> BitAnd
Rule : Compare --> BitOrXOR
Rule : EqualOrNot --> Compare
Rule : LogicNot -> EqualOrNot
Rule : Expr --> LogicNot
Rule : Statement --> 'See' Expr
==================================================================
==================================================================
Byte Code - Before Execution by the VM
==================================================================
PC OPCode Data
1 FuncExE
2 PushC Hello, World!
3 Print
4 ReturnNull
==================================================================
Hello, World!
Ring 编程语言是使用 PWCT 可视化编程工具设计的,您将在“visualsrc”文件夹中找到语言的视觉源文件(*.ssf 文件),在 src 文件夹和 include 文件夹中找到生成的源代码(用 C 语言编写)。在 GitHub 上 Fork 我。
下一个截图演示了我的意思,关于可视化实现
该语言不区分行,您不需要在语句后写 ;
,也不需要按 ENTER 或 TAB,因此我们可以写以下代码
See "The First Message" See " Another message in the same line! " + nl
以下代码创建了一个名为 Point
的类,其中包含三个属性 X
、Y
和 Z
。没有使用关键字来结束包/类/函数的定义。此外,我们可以直接在类名下方写属性名。
我们可以在定义之前使用类和函数。在此示例中,我们将创建一个新对象,设置对象属性,然后打印对象值。
代替使用点 '.' 运算符来访问对象属性和方法,我们可以使用大括号 { } 来访问对象,然后我们可以使用对象的属性和方法。
o1 = New point { x=10 y=20 z=30 } See O1 Class Point X Y Z
现在,我们将在通过 { } 访问对象后调用方法。
oPerson = new Person
{
Name = "Somebody"
Address = "Somewhere"
Phone = "0000000"
Print() # here we call the Print() method
}
Class Person Name Address Phone
Func Print
See "Name :" + name + nl +
"Address :" + Address + nl +
"Phone : " + phone + nl
当我们使用 { }
访问对象时,然后写入任何属性名,语言将检查该类是否有任何 setter/getter 方法将被自动调用。
在通过 { }
访问对象后,如果该类包含一个名为 BraceEnd()
的方法,它将被执行!
TimeForFun = new journey
# The first surprise!
TimeForFun {
Hello it is me # What a beatiful programming world!
}
# Our Class
Class journey
hello=0 it=0 is=0 me=0
func GetHello
See "Hello" + nl
func braceEnd
See "Goodbye!" + nl
接下来的示例演示了如何创建一个定义两个指令的类
- 第一个指令是:我想要一个窗口
- 第二个指令是:窗口标题 = 表达式
还可以忽略关键字,例如“the
”关键字
New App
{
I want window
The window title = "hello world"
}
Class App
# Attributes for the instruction I want window
i want window
nIwantwindow = 0
# Attributes for the instruction Window title
# Here we don't define the window attribute again
title
nWindowTitle = 0
# Keywords to ignore, just give them any value
the=0
func geti
if nIwantwindow = 0
nIwantwindow++
ok
func getwant
if nIwantwindow = 1
nIwantwindow++
ok
func getwindow
if nIwantwindow = 2
nIwantwindow= 0
see "Instruction : I want window" + nl
ok
if nWindowTitle = 0
nWindowTitle++
ok
func settitle cValue
if nWindowTitle = 1
nWindowTitle=0
see "Instruction : Window Title = " + cValue + nl
ok
我们学会了如何使用自然语句来执行代码,并利用相同的功能,我们可以使用嵌套结构来执行代码。.
以下来自 Web 库的示例,使用 Bootstrap 库生成 HTML 文档。此示例中没有直接编写 HTML 代码,我们创建了一个类似的语言(仅作示例)。然后,使用这种使用嵌套结构的声明式语言,我们生成了 HTML 文档。
此示例中的思路是,GetDiv()
和 GetH1()
方法返回一个对象,我们可以使用 {} 访问它,并且在每次对象访问后,BraceEnd()
方法将被执行,将生成的 HTML 发送到父对象,直到达到根对象,此时 BraceEnd()
将打印输出。
Load "weblib.ring"
Import System.Web
Func Main
BootStrapWebPage()
{
div
{
classname = :container
div
{
classname = :jumbotron
H1 { text("Bootstrap Page") }
}
div
{
classname = :row
for x = 1 to 3
div
{
classname = "col-sm-4"
H3 { html("Welcome to the Ring programming language") }
P { html("Using a scripting language is very fun!") }
}
next
}
}
}
为声明式界面提供支持的类如下所示
Class Link from ObjsBase
title link
Func braceend
cOutput = nl+GetTabs() + "<a href='" +
Link + "'> "+ Title + " </a> " + nl
Class Div from ObjsBase
Func braceend
cOutput += nl+'<div'
addattributes()
AddStyle()
getobjsdata()
cOutput += nl+"</div>" + nl
cOutput = TabMLString(cOutput)
将 Ring 编程语言嵌入 C/C++ 项目
我们可以使用 C/C++ 程序中的 Ring 语言,使用以下函数
RingState *ring_state_init();
ring_state_runcode(RingState *pState,const char *cCode);
ring_state_delete(RingState *pState);
核心思想是使用 ring_state_init()
创建 Ring 解释器的新状态,然后调用 ring_state_runcode()
函数来使用相同状态执行 Ring 代码。完成后,调用 ring_state_delete()
来释放内存。
#include "ring.h"
#include "stdlib.h"
int main(int argc, char *argv[])
{
RingState *pState = ring_state_init();
printf("welcome\n");
ring_state_runcode(pState,"see 'hello world from the ring programming language'+nl");
ring_state_delete(pState);
}
当然,上一个示例无法使用在线版本的语言进行测试,因为您需要 C 编译器 + Ring 语言的头文件和库(您可以从源代码构建)。
Ring API 附带以下函数来创建和删除状态。我们还有创建新变量和获取变量值的函数。
RingState * ring_state_init ( void ) ;
RingState * ring_state_delete ( RingState *pRingState ) ;
void ring_state_runcode ( RingState *pRingState,const char *cStr ) ;
List * ring_state_findvar ( RingState *pRingState,const char *cStr ) ;
List * ring_state_newvar ( RingState *pRingState,const char *cStr ) ;
void ring_state_main ( int argc, char *argv[] ) ;
void ring_state_runfile ( RingState *pRingState,const char *cFileName ) ;
我们可以在同一个程序中创建多个 Ring 状态,并且可以创建和修改变量值。
要获取变量列表,我们可以使用 ring_state_findvar()
函数。
要创建新变量,我们可以使用 ring_state_newvar()
函数。
示例
#include "ring.h"
#include "stdlib.h"
int main(int argc, char *argv[])
{
List *pList;
RingState *pState = ring_state_init();
RingState *pState2 = ring_state_init();
printf("welcome\n");
ring_state_runcode
(pState,"see 'hello world from the ring programming language'+nl");
printf("Again from C we will call ring code\n");
ring_state_runcode(pState,"for x = 1 to 10 see x + nl next");
ring_state_runcode(pState2,"for x = 1 to 5 see x + nl next");
printf("Now we will display the x variable value from ring code\n");
ring_state_runcode(pState,"see 'x value : ' + x + nl ");
ring_state_runcode(pState2,"see 'x value : ' + x + nl ");
pList = ring_state_findvar(pState,"x");
printf("Printing Ring variable value from C , %.0f\n",
ring_list_getdouble(pList,RING_VAR_VALUE));
printf("now we will set the ring variable value from C\n");
ring_list_setdouble(pList,RING_VAR_VALUE,20);
ring_state_runcode(pState,"see 'x value after update : ' + x + nl ");
pList = ring_state_newvar(pState,"v1");
ring_list_setdouble(pList,RING_VAR_VALUE,10);
pList = ring_state_newvar(pState,"v2");
ring_list_setdouble(pList,RING_VAR_VALUE,20);
ring_state_runcode(pState,"see 'v1 + v2 = ' see v1+v2 see nl");
ring_state_runcode(pState,"see 'end of test' + nl");
ring_state_delete(pState);
ring_state_delete(pState2);
}
输出
welcome
hello world from the ring programming language
Again from C we will call ring code
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
Now we will display the x variable value from ring code
x value : 11
x value : 6
Printing Ring variable value from C , 11
now we will set the ring variable value from C
x value after update : 20
v1 + v2 = 30
end of test
使用 C/C++ 代码扩展 Ring VM
我们可以通过添加用 C 或 C++ 编写的新函数来扩展 Ring 虚拟机(RingVM)。RingVM 附带许多用 C 编写的函数,我们可以像调用任何 Ring 函数一样调用它们。
我们可以通过编写新函数然后重新构建 RingVM 来扩展语言,或者我们可以创建一个共享库(DLL/So)文件来扩展 RingVM,而无需重新构建它。
每个模块函数可能包含以下步骤
- 检查参数数量
- 检查参数类型
- 获取参数值
- 代码/调用函数
- 返回值
结构与任何函数(输入 - 处理 - 输出)非常相似。但在这里,我们将使用 Ring API 来完成步骤 1、2、3 和 5。
以下代码表示使用 Ring API 和 C 的 sin()
函数实现的 sin()
函数。
void ring_vm_math_sin ( void *pPointer )
{
if ( RING_API_PARACOUNT != 1 ) {
RING_API_ERROR(RING_API_MISS1PARA);
return ;
}
if ( RING_API_ISNUMBER(1) ) {
RING_API_RETNUMBER(sin(RING_API_GETNUMBER(1)));
} else {
RING_API_ERROR(RING_API_BADPARATYPE);
}
}
您可以通过此教程阅读更多关于扩展的内容。
此外,您还可以使用 Ring 附带的代码生成器来快速生成 C/C++ 函数/类的包装器。
编辑器支持
您可以使用任何编辑器来使用该语言,Ring 团队还为 Notepad++、SubLime Text 2、Geany Editor、Visual Studio 和 Atom 编辑器提供了扩展。
下一个截图演示了在 SubLime Text 2 中使用 Ring。
下一个截图演示了在 Atom(我最喜欢的代码编辑器)中使用 Ring。
使用 RingAllegro 进行图形和 2D 游戏编程
您可以通过此教程了解如何通过 Ring 语言使用 Allegro 游戏编程库。
下一个示例显示并旋转图像
Load "gamelib.ring"
al_init()
al_init_image_addon()
display = al_create_display(640,480)
al_set_target_bitmap(al_get_backbuffer(display))
al_clear_to_color(al_map_rgb(255,255,255))
image = al_load_bitmap("man2.jpg")
al_draw_rotated_bitmap(image,0,0,250,250,150,0)
al_draw_scaled_bitmap(image,0,0,250,250,20,20,400,400,0)
al_flip_display()
al_rest(2)
al_destroy_bitmap(image)
al_destroy_display(display)
下一个屏幕截图展示了应用程序在运行时的情况
Web 开发
目前,Ring 编程语言附带一个简单的 CGI 库,用于创建 Web 应用程序。
Hello World 程序
#!b:\ring\ring.exe -cgi
Load "weblib.ring"
Import System.Web
WebPage()
{
Text("Hello World!")
}
该库是用 Ring 编写的(约 5K 行代码)。
下一个截图演示了该库的强大功能,它使用了面向对象编程和 MVC 设计模式。
您可以从此教程阅读更多关于该库的信息。
桌面和移动应用程序(使用 RingQt)
下一个示例询问用户姓名,然后说“你好!”
Load "guilib.ring"
MyApp = New qApp {
win1 = new qWidget() {
setwindowtitle("Hello World")
setGeometry(100,100,400,130)
label1 = new qLabel(win1) {
settext("What is your name ?")
setGeometry(10,20,350,30)
setalignment(Qt_AlignHCenter)
}
btn1 = new qpushbutton(win1) {
setGeometry(10,200,100,30)
settext("Say Hello")
setclickevent("pHello()")
}
btn2 = new qpushbutton(win1) {
setGeometry(150,200,100,30)
settext("Close")
setclickevent("pClose()")
}
lineedit1 = new qlineedit(win1) {
setGeometry(10,100,350,30)
}
layout1 = new qVBoxLayout() {
addwidget(label1)
addwidget(lineedit1)
addwidget(btn1)
addwidget(btn2)
}
win1.setlayout(layout1)
show()
}
exec()
}
Func pHello
lineedit1.settext( "Hello " + lineedit1.text())
Func pClose
MyApp.quit()
下一个屏幕截图展示了应用程序在运行时的情况。
您可以在此教程中阅读更多关于使用 Ring 进行 GUI 开发的信息。
该教程提供了许多示例,包括一个使用 RingQt 开发的简单纸牌游戏,每个玩家发 5 张牌,牌对任何人都未知。每次玩家点击一张牌查看时,如果这张牌与其他牌相同,玩家将获得可见牌的积分。如果牌的值是“5
”,玩家将获得所有可见牌的积分。
在移动设备(Android)上运行游戏时的下一个屏幕截图
关注点
Ring 是一种多范式语言,它将为您提供选择最适合您问题的范式的机会。
尝试使用该语言(它是免费开源的),然后考虑利用该语言的强大功能(声明式编程和自然编程)来创建新项目(框架),我相信您一定会成功。
我们需要贡献者,请随时加入并帮助我们(改进我们的代码、添加功能、报告错误、修复一些错误!、编写库、提供扩展、编写文档等)
历史
- 2016 年 1 月 25 日:Ring 1.0 发布!
- 2015 年 9 月:大部分文档已编写完成!
- 2015 年 8 月:大部分测试已完成!
- 2015 年 5 月:编译器和虚拟机的大部分工作已完成!
- 2015 年 4 月:语言名称:Ring
- 2013 年 9 月:语言的设计和实现已开始!
- 2011 年 11 月:新编程语言的理念和总体目标