四香油饼 发表于 7-2-2010 23:50:27

我的第一个c++程序

终于写完了我的第一个c++程序,不是gui的,是个控制台程序,功能是我需要的一个实用小转换程序。A单片机的C编译器很好用,但芯片稍贵,B单片机台湾出的,便宜,但C编译器很烂,两种单片机的汇编语言有90%的相似度,这个小程序用于把A单片机的汇编源程序转化成B单片机的语言。这样,就可以用A的C编译器来开发B了。

写了半天,数了数才200行左右的程序,离我3000行的目标还有很大差距阿:'(

把程序贴上来,给自己留个纪念,如果哪位老师有闲工夫,也非常欢迎来给俺提些程序的改进意见。

#ifndef INSTRUCTION_H
#define INSTRUCTION_H
#include <string>

class Rule
{
public:
        Rule(const std::string& rule);
        std::string Name;
        std::string Out;
};

class Command
{
public:
        Command(const std::string& In);
        std::string Label;
        std::string InstructName;
        std::string u;
        std::string v;
        std::string Comments;
};
#endif


#include "instruction.h"
#include <string>
using namespace std;

Rule::Rule(const string& rule)
{
        size_tPos1, Pos2, Pos3;
        Pos1 = rule.find('=');
        Pos2 = rule.find_first_not_of(" \t",Pos1+1);
        if (Pos2 != string::npos)
        {
                Out = rule.substr(Pos2);
        }
        else
        {

                Out.clear();
        }
        Pos2 = rule.find_first_not_of(" \t");
        Pos3 = rule.find_first_of(" \t",Pos2+1);
        if (Pos2 < Pos1)
        {
                Name = rule.substr(Pos2,Pos3 >= Pos1 ? Pos1-Pos2 : Pos3-Pos2);
        }
        else
        {
                Name.clear();
        }
}

Command::Command(const string& In)
{
        string Line;
        int Pos, Pos1;
        Line = In;
        Pos = Line.find(';');
        if (Pos != string::npos)        // if there are comments
        {
                Comments = Line.substr(Pos);
                Line.erase(Pos);        // get and erase comments from string
        }
        else                // there's no comment
        {
                Comments.clear();
        }
        v.clear();
        Pos = Line.find(',');
        if(Pos != string::npos)        // if there's parameter
        {
                v = Line.substr(Pos+1);
                Line.erase(Pos);
        }
        u.clear();
        InstructName.clear();
        Label.clear();
        Pos = 0;
        if ((Line != ' ') && (Line != '\t'))                // if there's Label
        {
                Pos = Line.find_first_of(" \t");
                Label = Line.substr(0,Pos);
        }
        Pos1 = Line.find_first_not_of(" \t",Pos);
        if (Pos1 != string::npos)                // if there's command name
        {
                Pos = Line.find_first_of(" \t",Pos1);
                if (Pos != string::npos)
                {
                        InstructName = Line.substr(Pos1, Pos-Pos1);        // what if Pos=npos??
                }
                else
                {
                        InstructName = Line.substr(Pos1);
                }
                Line.erase(0,Pos);
                if (!Line.empty())
                {
                        Pos = Line.find_first_not_of(" \t");
                        if (Pos != string::npos)
                        {
                                u = Line.substr(Pos);        // remove label and name, left is
                        }
                }
        }
}




#include "instruction.h"
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
using namespace std;


int main(int argc, char* argv[])
{
        ifstream fin, PIC_asm;
        ofstream fout;
        string line, out;
        vector<Rule> Table;
        size_t Pos;
        Command* Source;

        if (argc < 2)
        {
                cout << "usage: convert source.as" << endl << "Please provide source file name." << endl;
                return(0);
        }
        fin.open(argv);
        fin.close();
        if (fin.fail())
        {
                cout << argv << " does not exist, please check again!" << endl;
                return(0);
        }
        fin.open("rules.txt");
        fin.close();
        if (fin.fail())
        {
                cout << "rules.txt not exist" << endl;
                return (0);
        }
        fin.open("rules.txt");
        int i=0;
        while (getline(fin, line))
        {
                cout << line << endl;
                if (line.find('=') != string::npos)
                {
                        Table.push_back(Rule(line));
                }
        }
        fin.close();
        string OutfileName(argv);
        Pos = OutfileName.rfind('.');
        OutfileName = OutfileName.substr(0, Pos)+".dt";
        fin.open(OutfileName.c_str());
        fin.close();
        if (!fin.fail())
        {
                cout << OutfileName << " exists, do you want to overwrite? ";
                while (1)
                {
                        cin >> line;
                        if ((line == "y") || (line == "yes") || (line == "Y") || (line == "YES"))
                        {
                                break;
                        }
                        else if ((line == "N") || (line == "n"))
                        {
                                return (0);
                        }
                }
        }
        fout.open(OutfileName.c_str());
        if (fout.fail())
        {
                cout << "Error openning " << OutfileName << " !" << endl;
                fout.close();
                return (0);
        }
        fin.open(argv);
        fin.seekg(0);
        cout << "\nSource file :" << endl;
        while (getline(fin,line))
        {
                cout << line << endl;
        }
        fin.seekg(0);
//        cout << endl << endl << endl << "The source file:" << endl;
        fin.close();
        PIC_asm.open(argv);
        while (getline(PIC_asm,line))
        {
//                cout << line << "    CONVERT TO    " ;
                if (!line.empty() && (line.find_first_not_of(" \t") != string::npos))
                {
                        Source = new Command(line);
                        int i;
                        size_t Pos1;
                        for (i=0; i<Table.size(); i++)
                        {
                                if(Table.Name == Source->InstructName)
                                {
                                        break;
                                }
                        }
                        if (i == Table.size())
                        {
                                out = "; " + Table.Out + " : " + Source->InstructName;
                        }
                        else
                        {
                                out = Table.Out;
                        }
                        if (!out.empty())
                        {
                                Pos1 = out.find("");
                                if (Pos1 != string::npos)
                                {
                                        out = out.replace(Pos1,3,Source->u);
                                }
                                Pos1 = out.find("");
                                if (Pos1 != string::npos)
                                {
                                        out = out.replace(Pos1,3,Source->v);
                                }
                        }
                        fout << Source->Label << '\t' << out << '\t' << Source->Comments;
                        fout << endl;
                        delete Source;
                }
                else
                {
                        cout << line << endl;
                }
        }
        PIC_asm.close();
        fout.close();
        cout << "*** Conversion completed. File \"" << OutfileName << "\" is created." << endl;
        return (0);
}



; ### PIC to EMC asm converting rules
bsf ,        =        BS ,
bcf ,        =        BC ,
movlw         =        MOV A,@
                =       
                =        Unknown Command
test.dt exists, do you want to overwrite? y

Source file :
        bsf        ads,2
        bcf        5,6        ; hello
        movlw        0x38
; test line
        movfw        3,b


Loop:        movlw        25




*** Conversion completed. File "test.dt" is created.
jian@jian-laptop:~/codes/convert$ cat test.dt
        BS ads,2       
        BC 5,6                ; hello
        MOV A,@0x38       
                ; test line
        ; Unknown Command : movfw       
Loop:        MOV A,@25       
jian@jian-laptop:~/codes/convert$

关毅仁 发表于 8-2-2010 00:32:50

不错,很干净,很整齐。

ubuntuhk 发表于 8-2-2010 00:33:03

回复 #1 四香油饼 的帖子

程序写得相当工整,赞一下:good :good

一点小建议:
1.可以把“using namespace std;”放到instruction.h里面,这样在instrction.h里面就可以不用引用“std::"了。

2.如果有比较的时候,可以把变量写在后面,常量写在前面,避免变量被误赋值(这种bug如果发生了,不好找),比如: if ((line == "y") || (line == "yes") || (line == "Y") || (line == "YES"))建议改为: if (("y" ==line) || ("yes"==line) || ("Y"==line) || ("YES"==line))3.如果在FreeOZ帖代码,建议用code标签而不是quote标签,这样可以避免代码被转为其它符号:【code】 your code 【/code】(把【】改为[])

GPS 发表于 8-2-2010 14:08:03


1.可以把“using namespace std;”放到instruction.h里面,这样在instrction.h里面就可以不用引用“std::"了。

好像记得有本书讲不要在header里放using namespace。

GPS 发表于 8-2-2010 14:22:34

是不是把Rule和Command放在两个文件的好点?
而且,好像两个类的成员都是只读的?是不是应该把他们都搞成private然后用个 const的getter 函数?如果要写,就加个setter, 不过偷懒的时候就都是public. 呵呵,我只是积极举手问答, 等评语吧。

michaelchin 发表于 8-2-2010 14:33:49

原帖由 GPS 于 8-2-2010 14:08 发表 http://freeoz.org/bbs/images/common/back.gif

好像记得有本书讲不要在header里放using namespace。
有书这样说

coolmate 发表于 8-2-2010 14:34:06

类的成员变量,无特殊需要,一律要私有。
类的成员函数,只有自身调用的,私有。
类的成员的名称,一律小写,并且私有、保护的要和公开的有区别。
一个类,放在一个file里面。
尽量避免使用:
using namespace std
这样的声明,让code更清晰。

还有很多,慢慢来吧。

michaelchin 发表于 8-2-2010 14:34:14

原帖由 GPS 于 8-2-2010 14:22 发表 http://freeoz.org/bbs/images/common/back.gif
是不是把Rule和Command放在两个文件的好点?
而且,好像两个类的成员都是只读的?是不是应该把他们都搞成private然后用个 const的getter 函数?如果要写,就加个setter, 不过偷懒的时候就都是public. 呵呵,我只是 ...
时髦的用visitor

coolmate 发表于 8-2-2010 14:35:43

本帖最后由 coolmate 于 12-9-2016 00:59 编辑

这是我的一个小文件的定义文件,你可以看一下。#ifndef HELP_H
#define HELP_H

#include <string>

namespace a {
namespace b{

    class help
    {

    public:

      ~help();                                                       //Desctructor
      help(std::string class_name, std::string command = "");      //Constructor
      help();                                                      //Empty constructor

      std::string result();                                          //Get the search result
      std::string get_classrange();                                  //Get class name to search
      const void set_classrange(const std::string range);            //Set the class to be searched
      const void set_searchitem(const std::string item);             //Set the item name to be searched
      void search();                                                 //Actual search function
      bool is_success();                                             //show whether the search is successful

    private:

      bool success_;                                                 //Indicator of success
      std::string class_range_;                                    //Class name in which the command to be searched
      std::string search_item_;
      std::string result_;                                           //Command to be searched
    };

} } //namespace a::b::help

#endif //HELP_H

Port_1433 发表于 8-2-2010 14:44:13

原帖由 关毅仁 于 8-2-2010 00:32 发表 http://www.freeoz.org/bbs/images/common/back.gif
不错,很干净,很整齐。

大师是按照风水的原则看的么?:P :P :P

MacroJ 发表于 8-2-2010 14:56:43

看程序后,发现C++都几乎忘光了:'(

GPS 发表于 8-2-2010 15:17:05

原帖由 coolmate 于 8-2-2010 14:35 发表 http://www.freeoz.org/bbs/images/common/back.gif
这是我的一个小文件的定义文件,你可以看一下。#ifndef NICTA_SISM_HELP_H
#define NICTA_SISM_HELP_H

#include

namespace nicta {
namespace sism {

    class help
    {

    public:

      ...
是不是用const函数好点阿?
std::string result() const;
std::string get_classrange() const;
用get_result, get_classrange, 或者result, classrange应该更一致点.

[ 本帖最后由 GPS 于 8-2-2010 15:19 编辑 ]

coolmate 发表于 8-2-2010 15:47:22

原帖由 GPS 于 8-2-2010 15:17 发表 http://www.freeoz.org/bbs/images/common/back.gif

是不是用const函数好点阿?
std::string result() const;
std::string get_classrange() const;
用get_result, get_classrange, 或者result, classrange应该更一致点.

你说的对。这就改。至于const的,这一点我到现在也没真正弄清楚它的真正优点。我们这里有一个c++委员会的member,我是他教出来的。很多时候还是不能完全满足他的要求,即使是code的风格上。呵呵

GPS 发表于 8-2-2010 16:22:37

原帖由 coolmate 于 8-2-2010 15:47 发表 http://www.freeoz.org/bbs/images/common/back.gif

我们这里有一个c++委员会的member,我是他教出来的。

哇,你真幸福阿,呵呵。能不能把你们的coding规范还有培训教材什么的共享一下阿?呵呵。

coolmate 发表于 8-2-2010 16:32:33

原帖由 GPS 于 8-2-2010 16:22 发表 http://www.freeoz.org/bbs/images/common/back.gif


哇,你真幸福阿,呵呵。能不能把你们的coding规范还有培训教材什么的共享一下阿?呵呵。

呵呵,是很幸福。那家伙太NB,以至于很多地方不敢用他,因为他的code用起来很简单,理解起来很难,人家怕他走了,再也没有人能接过去干。所有的code全都是模板封装的。

至于规范和材料,那是严禁泄露的。呵呵,对不起哦。

蒙面超人 发表于 8-2-2010 17:07:06

回复 #15 coolmate 的帖子

太幸福了。。。。羡慕

四香油饼 发表于 8-2-2010 18:50:45

原帖由 coolmate 于 8-2-2010 14:34 发表 http://www.freeoz.org/bbs/images/common/back.gif
类的成员变量,无特殊需要,一律要私有。
类的成员函数,只有自身调用的,私有。
类的成员的名称,一律小写,并且私有、保护的要和公开的有区别。
一个类,放在一个file里面。
尽量避免使用:
using namespace...

我这个小破程序引来这么多高人,真高兴,大家以后要多指点阿。
这位达人,俺有几个地方不太清楚,再请教一下:
1。关于变量的命名,一直比较糊涂,看过的程序也有很多种不同的风格,能不能讲讲你们的变量命名规则?这个应该不是保密的范围吧,我没经过系统学习,所以很多基本的东西都不清楚,大致讲讲吧。
2。这个一个类放在一个文件里,如果是base和derived类呢?也分开放吗?
3。对于namespace,一直感到比较深奥,在什么情况下要自己定义namespace呢?像你的程序里面写的,把这个help这个类放在了nicta这个namespace里面,有什么好处呢?那以后程序里面除了include "nicta_sism_help.h" 以外,如果要使用这个类不是还得写nicta::sism::,作用是什么呢?

另外还有一个问题,不是关于coolmate的程序的,是一般编程的问题,如果有一组没规律的数,现在想检验另外一个数是否与这组数中的一个相等,一定要用循环的办法全部比较一遍吗?有没有什么好的办法??

看coolmate高人写程序这么严谨,应该不是搞应用开发的,能大概透露一下一门公司干啥的么?让我仰慕一下。:lol

四香油饼 发表于 8-2-2010 19:00:32

原帖由 coolmate 于 8-2-2010 16:32 发表 http://www.freeoz.org/bbs/images/common/back.gif


呵呵,是很幸福。那家伙太NB,以至于很多地方不敢用他,因为他的code用起来很简单,理解起来很难,人家怕他走了,再也没有人能接过去干。所有的code全都是模板封装的。

至于规范和材料,那是严禁泄露的。呵呵 ...


别人看不懂的程序有两种,一种是太牛了,一种是太烂了。俺的程序别人理解起来也很困难,不过俺是后一种的

ubuntuhk 发表于 8-2-2010 20:17:55

回复 #17 四香油饼 的帖子



另外还有一个问题,不是关于coolmate的程序的,是一般编程的问题,如果有一组没规律的数,现在想检验另外一个数是否与这组数中的一个相等,一定要用循环的办法全部比较一遍吗?有没有什么好的办法??


如果数比较少的话,用循环可能是最简单的办法,如果比较多,循环一边效率低的话,可以用hash表来快速查找。

ubuntuhk 发表于 8-2-2010 20:33:12

原帖由 GPS 于 8-2-2010 14:08 发表 http://www.freeoz.org/bbs/images/common/back.gif

好像记得有本书讲不要在header里放using namespace。

在网上搜了一下,这个说法比较有道理,摘录过来:
http://topic.csdn.net/u/20080327/13/dfea9d61-fd59-47c5-b3a5-293f357419e7.html (9楼)

头文件会被很多文件include,这里std空间里的名字全进入了全局名字空间. 造成名字污染!

如果在外面把std using使std进入全局名字空间,那C++为什么还要把标准库的名字放在std?

<thinking in c++> 强烈建议不能在header文件中using namespace std; <C++必知必会>认为在header file中using namespace std"是个馊主义...基本上又退回到了原点."

我查C++primer,但没有找到好的方法.
      using std::string;
      using std::map;
      ....
这样做了.敲字母都敲到手痛.

ubuntuhk 发表于 8-2-2010 20:39:29

回复 #17 四香油饼 的帖子

变量命名风格,我个人觉得同一个项目中只要采用一套一致变量命名风格即可,当然如果所有的项目都采用同样的命名风格更好。

还是从网上搜到的一些相关文章,大家一起讨论分享一下:
《Google C++ Style Guide》: http://www.cppblog.com/Fox/archive/2008/07/22/56845.html
《你如何命名变量?是否推荐匈牙利命名法? by C++之父》:http://stdcpp.cn/html/24/26/0709/313.htm
(原文在:http://www2.research.att.com/~bs/bs_faq2.html#Hungarian,这里还有不少关于c++方面的建议)

coolmate 发表于 8-2-2010 20:47:01

原帖由 ubuntuhk 于 8-2-2010 20:17 发表 http://www.freeoz.org/bbs/images/common/back.gif


如果数比较少的话,用循环可能是最简单的办法,如果比较多,循环一边效率低的话,可以用hash表来快速查找。
我很赞同。呵呵。没有分了。。

stellahie 发表于 8-2-2010 20:47:17

回复 #15 coolmate 的帖子

太幸福了。。。。羡慕

(有分加吗?):yct_32

coolmate 发表于 8-2-2010 20:47:58

太幸福了。。。。羡慕
呵呵。没有分了。。

[ 本帖最后由 coolmate 于 8-2-2010 20:49 编辑 ]

蒙面超人 发表于 8-2-2010 20:54:56

原帖由 四香油饼 于 8-2-2010 15:50 发表 http://www.freeoz.org/bbs/images/common/back.gif


我这个小破程序引来这么多高人,真高兴,大家以后要多指点阿。
这位达人,俺有几个地方不太清楚,再请教一下:
1。关于变量的命名,一直比较糊涂,看过的程序也有很多种不同的风格,能不能讲讲你们的变量命名 ...


2. 分开放会比较容易管理,derived类可能有n个,写在一个head里面不便于协同合作。其实这些都是习惯,我一直没有荣幸接触真正了解c++标准的,所以我的风格相当飘逸~~~:loveliness: :loveliness:

菜鸟见了都会笑

coolmate 发表于 8-2-2010 20:58:44

本帖最后由 coolmate 于 12-9-2016 01:01 编辑

原帖由 四香油饼 于 8-2-2010 18:50 发表 http://www.freeoz.org/bbs/images/common/back.gif


我这个小破程序引来这么多高人,真高兴,大家以后要多指点阿。
这位达人,俺有几个地方不太清楚,再请教一下:
1。关于变量的命名,一直比较糊涂,看过的程序也有很多种不同的风格,能不能讲讲你们的变量命名 ...
简单说说:
1。变量命名:一律用小写字母,如果有多个section,用下划线链接,如果是保护乘员和私有成员,用下划线结尾。包括函数名。
2。base类自然是一个文件,但是如果这个基类只是一个非常简单的东西,而且你确定没有其他派生类,可以同派生类放在一起。但是这样的话,也就失去了基类存在的意义
3。对于小程序,使用namespace没有什么显著的好处,但在大型开发里面,坚定、清晰并一致地使用namespace,可以极大地是程序清晰可读。尤其是在你有多个类并有多个同样或者类似的函数名称的时候。n_a::n_b::n_c1::foo() will tell it clearly from n_a::n_c::n_d::foo()。这样做,虽然增加了键入时的麻烦,但是习惯了之后,你会觉得非常方便。

呵呵,确实,我现在做的不是一般的应用,而是贴近于research的东西,不过从另一方面说,是一个parser和开发环境的融合体。至于实用价值,不知道。

coolmate 发表于 8-2-2010 21:00:10

我的分分呢?为什么不能加分啊。。。

fred_au 发表于 9-2-2010 00:22:14

我记得以前Windows下编程都遵循匈牙利命名法,可能是因为M$的SDK都是用的这种命名法吧。 后来皈依Linux之后,就都是小写字母加下划线了。

薛定谔猫 发表于 9-2-2010 00:44:07

原帖由 coolmate 于 8-2-2010 14:35 发表 http://www.freeoz.org/bbs/images/common/back.gif
这是我的一个小文件的定义文件,你可以看一下。#ifndef NICTA_SISM_HELP_H
#define NICTA_SISM_HELP_H

#include

namespace nicta {
namespace sism {

    class help
    {

    public:

      ...
这段代码挺干净的,就是这点比较奇怪:

const void set_classrange(const std::string range);            //Set the class to be searched
      const void set_searchitem(const std::string item);             //Set the item name to be searched



前面的const void干嘛的? 一般如果method不修改class成员,应该用const做后缀说明,如果返回的是引用,但是又不想被修改,用const T&, 如果是RBV (return by value),就啥都不用修饰。可是你这里,返回是void,我第一次看到特意弄个const void的,能不能说明下用意?

coolmate 发表于 9-2-2010 10:02:08

原帖由 fred_au 于 9-2-2010 00:22 发表 http://www.freeoz.org/bbs/images/common/back.gif
我记得以前Windows下编程都遵循匈牙利命名法,可能是因为M$的SDK都是用的这种命名法吧。 后来皈依Linux之后,就都是小写字母加下划线了。
匈牙利命名法其实是一个很受争议的方法,即使在windows下也不是每个人都喜欢的。
页: [1] 2 3
查看完整版本: 我的第一个c++程序