我设计的单片机C语言编译器,大家看有用吗

[复制链接]
17308|91
手机看帖
扫描二维码
随时随地手机跟帖
0xCC|  楼主 | 2010-1-26 00:13 | 显示全部楼层 |阅读模式
本帖最后由 0xCC 于 2010-1-26 07:23 编辑

跟大家分享一个我做的单片机C语言编译器。它的功能和keil软件差不多,能把C语言
转换成单片机的汇编程序。不过目前还不完善,只支持MCS51系列的单片机,等以后有时间
我会把这个编译器移植到AVR和PIC系列的单片机上。虽然C语言很流行,但我个人感觉C的一些
细微地方并不适合单片机,因此在设计这个编译器时,有些语法和标准C有区别。例如,
这个编译器扩展了移位运算,移位时可以指定空出的位是用0还是1填充,也可以循环移位,
分别用 <<- <<+ <<< 等运算表示,还提供了一种扩展的控制语句: loop 。使用时
就像下面这样:
loop( 8 )
{
    语句a
}
表示执行8次语句a。实际是用djnz指令实现的,所以效率比for语句高。
对于变量类型则不再用标准C的char short long int 等名称,而是int+数字或uint+数字形式,
分别表示相应长度的有符号数和无符号数。例如下面的定义:
uint8 a = 0b00001111;//定义8位(一个字节)的无符号数,可以用二进制
int16 b = 12345;//定义16位(两个字节)有符号数
bit c = high;//定义位变量,赋值为1
bool 游戏结束 = true;//定义布尔类型变量
    (标识符、文件名和文件夹等可以任意取名,这个编译器非常支持中文 ^_^)
另外增加了一个特别的类型--“元件类型”,例如这样定义一个元件类型:
box s24c256 [uint16*8]
{
    interface void set( uint16 addr, uint8 data )
    {
        ...
    }
    interface uint8 get( uint16 addr )
    {
        ...
    }
}
其中set函数用来把一个字节变量data通过IIC总线写入24c256中,而get函数用来读取
地址为addr的那个存储单元的数据。只要定义了这个元件,就可以在外部的24c256中
定义变量和数组、结构体等,例如:
s24c256 uint8 data = 0b00001111;//在24c256中定义8位无符号数data并赋值15。
data可以像一般变量那样参与运算。当运算中需要读取data的值时,编译器会自动调用
get函数获取值,当运算中需要改变data的值时(如赋值运算data = 34 )编译器会
自动调用set函数把34写入到24c256中,用法和普通的变量完全一致。非常方便。
实际上只要一个电子元件中可以存放数据,你就可以在那里定义数据,如把一个数组定义
到一个128*64液晶屏显存中,那对这个数组操作时屏幕会有相应的变化,甚至可以在
另一个单片机中定义一个数组,只要用set和get封装了串口通信程序,就可以在其他单片机
中读取和修改这个数组的各元素,很有意思吧!
一个源程序由若干个这样的元件类型组成,每个元件中都可以定义静态变量、函数和接口等,
每个成员都可以带有public或private修饰符,当为public类型时表明这个函数或静态变量
可以在任意地方访问,当为private类型时只能被同一元件中的函数访问。
实际上这种新增的元件类型作用非常大,通过它还能实现位变量的数组定义等。目前
我正在想办法把元件类型用于库函数的配置,因为下一步我正在打算为这个编译器添加
库函数集合,这里的库函数不是通常的编译系统自带的字符串操作、各种浮点运算等函数,
而是其他电子元件的驱动程序,如24c系列的读写函数、温度检测ds18b20的读写函数、
ds1302计时芯片的读写和液晶屏1602、128*64等接口函数。但现在有一个问题是这些函数
都不是用#include包含之后就可以直接使用的,都要先进行配置,如24c系列存储器
函数需定义SCK和SDA对应单片机的哪两个引脚,液晶1602的数据线怎样和单片机连接等。
而这些配置应在用户程序中实现,而不是进入库函数文件夹修改库函数。我打算这样实现:
库函数由若干个元件定义如液晶屏元件,ds18b20元件等组成,当需要使用哪个元件时
用#include包含进来,而每个元件的配置变量分别用一个“配置元件”定义,当然这个定义
是由用户编写的,也就是说库函数会反向访问用户的程序和数据。完整方式如下:
文件 test.c:
#include "AT24C256.h";
box main
{
    void main()
    {
        AT24c256 uint16 data = 34;//在24c256中定义一个16位无符号数
        while( true ) {}
    }
}
box AT24c256_port //配置元件名称应为主元件名 + port
{
    public bit SCK = &P1_0;
    public bit SDA = &P1_1;
}
预计过年后给大家提供的下一个版本将会实现这种带库函数的编译器,因为库函数会反向访问
用户函数和数据,所以库函数将会以源代码的方式存放,而不像传统编译器那样以obj形式存放。
这样将会非常方便,代价仅仅是稍微增加了编译时间而已。
到目前为止,这个编译器还有些其他语法尚未实现,生成的hex代码也没有进行任何优化,
现在只是从“概念”上实现这种编程语言,至于优化则是以后的事情了。其他说明都在
编译器文件夹中,大家可以下载了看看。注意这个编译器是用C#设计的,本身不需要安装,
随便复制到哪个文件夹下都行,但运行需要微软的.NET环境,需要在网上搜一个netframework
安装之后编译器才能用(估计vista和win7的已经内置.NET 就不需安装了,不过没试过)。
希望各位高手有时间可以帮我测试一下,另外在语法方面我都想的头疼了,大家应该集思广益嘛,有好的建议可以邮箱联系:xbd2048@qq.com。让我们共同设计一个单片机专用的编程语言.
顺便再给大家拜个年 ^_^       C编译器.rar (648.88 KB)
评论
yld5168 2018-4-18 22:17 回复TA
很有参考价值。 

相关帖子

0xCC|  楼主 | 2010-1-26 07:37 | 显示全部楼层
我这个编译器可是全面支持中文啊,文件名和文件夹都可以带汉字,程序中的中文注释等不会出现KEIL的半个汉字的现象,连标识符如函数名和变量名都可以使用汉字,关键字也有不同的颜色,用着很方便的

使用特权

评论回复
0xCC|  楼主 | 2010-1-26 08:28 | 显示全部楼层
没有人对编译器感兴趣吗

使用特权

评论回复
mohanwei| | 2010-1-26 08:34 | 显示全部楼层
不错,有想法,支持一下。

使用特权

评论回复
mohanwei| | 2010-1-26 08:36 | 显示全部楼层
但是像loop(8)这种就没必要了,完全可以在优化的时候,检测到CPU为51,且次数小于256的时候用一种策略,大于256又用另一种策略……

使用特权

评论回复
mohanwei| | 2010-1-26 08:38 | 显示全部楼层
变量类型,建议也支持支持s8,s16,s32,u8,u16,u32写法……代码大了可以省很多事
至于通信传输,建议增加多平台移植相关的功能,例如直接发送一个结构体,就是很有意义的事。

使用特权

评论回复
0xCC|  楼主 | 2010-1-26 08:39 | 显示全部楼层
本帖最后由 0xCC 于 2010-1-26 08:40 编辑

不过用 loop( 8 ) {} 非常简单啊,我编了七个测试程序,有计算器,弹球游戏等全用loop语句解决了,
几乎没用 for 语句
loop( 8 )
{
      ...
}

int i;
for( i = 0; i < 8; i++ )
{
    ...
}
用法还是比for简单些嘛

使用特权

评论回复
0xCC|  楼主 | 2010-1-26 08:42 | 显示全部楼层
是啊, 变量类型就是这些名字  uint8 uint16 uint32   int8 int16 int32

使用特权

评论回复
computer00| | 2010-1-26 08:47 | 显示全部楼层
还是遵循标准好一些,不然以后代码移植就麻烦了。

使用特权

评论回复
mohanwei| | 2010-1-26 08:50 | 显示全部楼层
如果嫌写for()比较麻烦,可以在IDE中集成一种功能:点击右键,弹出菜单中有“插入for循环模板”,直接生成:
for(int  i = 0; i < 8; i++ )
{
    ...
}
再手工改一下“8”即可

使用特权

评论回复
0xCC|  楼主 | 2010-1-26 08:51 | 显示全部楼层
如果把编译器移植了,代码就不用改了.  如果这个还行的话,过年后回学校我就把它移植到AVR和PIC上

使用特权

评论回复
0xCC|  楼主 | 2010-1-26 08:55 | 显示全部楼层
loop可以直接翻译成 djnz 指令啊,这个在时间严格的地方如ds18b20中很有用,而KEIL中的for语句
的执行时间就不容易确定了吧,除非看到编译后的汇编代码

使用特权

评论回复
huangqi412| | 2010-1-26 09:08 | 显示全部楼层
咔咔,顶一把.        用WHILE 减减就可以了吧,还是遵循标准比较好,     扩展循环移位操作是个好东西.

使用特权

评论回复
jerkoh| | 2010-1-26 09:15 | 显示全部楼层
顶! 不做成标准的

最多有人好奇学习使用下

不会拿来编译项目代码的

使用特权

评论回复
southboy| | 2010-1-26 09:27 | 显示全部楼层
牛,相当的牛:victory:

使用特权

评论回复
OneMillion| | 2010-1-26 09:46 | 显示全部楼层
有意思。
楼主干脆就做一个可视化编程得了,

比如要用24C01,类似PROTEUS的仿真。将24C01和51单片机都放到原理图上面,
这样实物的连线可视化,无需了解怎么去配置端口的函数了,
然后再调用标准的 GET(),SET().

对于单片机的应用来说,定时器的配置是个问题。
楼主可以配置一个类似VC里面的 SetTimer(); KillTimer();
这样的函数,用户无需了解用了什么定时器,直接用这样标准的函数。

还有中断的处理。
也是基于对话框的,
每个中断向量编辑框中,放置配置代码。
就用标准的C代码。

暂时说这么多。。

使用特权

评论回复
xlsbz| | 2010-1-26 09:59 | 显示全部楼层
一定要按标准来啊  

否则 玩玩可以.....

记住 不要玩!!
开发国产编译器的大任就降落在楼主的身上了!!

使用特权

评论回复
computer00| | 2010-1-26 10:20 | 显示全部楼层
i=9;
while(--i)
{
}
同样就是楼主所要的loop(8)了。

使用特权

评论回复
0xCC|  楼主 | 2010-1-26 10:27 | 显示全部楼层
TO computer00:  在keil中是,不过我设计的这个编译器控制语句中的表达式必须返回布尔类型, 所以目前还不能那样写.呵呵

使用特权

评论回复
xlsbz| | 2010-1-26 10:31 | 显示全部楼层
i=9;
while(--i)
{
}
同样就是楼主所要的loop(8)了。
computer00 发表于 2010-1-26 10:20


大侠 近来似乎不怎么忙啊!!!

有空来看望大家了!......

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

8

主题

45

帖子

8

粉丝