编译原理学习一,去除代码中的注释

前言

开始学习编译原理了耶~ 关于编译原理的所有练习,按照老规矩,还是用我最喜欢的C#语言来实现,运行在.NetCore平台上~ 关于这个系列的所有代码已经上传到github了,项目主页:

github.com/Deali-Axy/C…

本次题目

对C或C++等高级程序设计语言编写的源程序中的//注释和//注释进行删除,保留删除后的源程序。要求以文件形式进行保存。

思路分析

程序主要功能就是消除已经编写好的源程序中的注释。在源程序中注释有两种形式,一种是单行注释,用“//”表示,另一种是多行注释,用“//”表示。针对这两种形式,程序中用了if..else..语句加以判断,并做出相应的处理。在这里还有可能出现另一种情况,上述两种注释符号可能出现在引号中,出现在引号中的注释符号并没有注释功能,因此在引号中出现的注释符号不应该被消除。所以,这次编写的程序将要分三种情况分析。

第一种情况,单行注释:
if (ch != temp)
{
    // 这里就是单行注释
    ofile.put(ch);
    ch = ifile.get();
}
复制代码

或者

if (ch != temp)
{
    /* 这里就是单行注释 */
    ofile.put(ch);
    ch = ifile.get();
}
复制代码
第二种情况,块注释:
if (ifile.fail() || ofile.fail())
{
    cerr << "open file fail\n";
    return EXIT_FAILURE;
    /*返回值EXIT_FAILURE(在cstdlib库中定义),用于向操作系统报*
    告打开文件失败*/
}
复制代码
第三种情况,行后注释:
ifile.close(); // 关闭文件
ofile.close();
cout << "/*ret/rtr";
system("pause");
return 0;
复制代码
还有一个关键的注意点

可以看到这一行

cout << "/*ret/rtr";
复制代码

这个字符串用双引号包起来的代码中有很多斜杠,所以要避免将这些斜杠识别为注释。 这里我用的方法是在处理注释前先把包含注释符号的字符串替换掉,等注释删除之后,再添加回去。

实现代码

注释写得很详细啦,配合上面的思路分析,我就不再继续分析代码了~

var sReader = new StreamReader(filePath);
var newSource = "";
var inBlock = false;
var replaceFlag = false;
var tempLine = ""; // 用于保存被替换的特殊行代码
while (!sReader.EndOfStream)
{
    var line = sReader.ReadLine();
    if (line.Length == 0) continue; // 去除空行

    var quotationPattern = "^(.*?)\".*//.*\"";
    var quotationResult = Regex.Match(line, quotationPattern);
    if (quotationResult.Success)
    {
        System.Console.WriteLine("替换特殊代码,双引号中包裹注释斜杠");
        tempLine = quotationResult.Groups[0].Value;
        replaceFlag = true;
        line = Regex.Replace(line, quotationPattern, REPLACEMENT);
    }

    // 单行注释
    if (line.Trim().StartsWith(@"//"))
        continue;
    if (line.Trim().StartsWith(@"/*") && line.EndsWith(@"*/"))
        continue;

    // 注释块
    if (Regex.Match(line.Trim(), @"^/\*").Success)
        inBlock = true;
    if (Regex.Match(line.Trim(), @"\*/$").Success)
    {
        inBlock = false;
        continue;
    }

    // 行后注释
    // 使用非贪婪模式(.+?)匹配第一个//
    var pattern = @"^(.*?)//(.*)";
    // var pattern = @"[^(.*?)//(.*)]|[^(.*?)/\*(.*)\*/]";
    var result = Regex.Match(line, pattern);
    if (result.Success)
    {
        System.Console.WriteLine("发现行后注释:{0}", result.Groups[2]);
        line = result.Groups[1].Value;
    }

    // 还原被替换的代码
    if (replaceFlag)
    {
        System.Console.WriteLine("还原特殊代码");
        line = line.Replace(REPLACEMENT, tempLine);
        replaceFlag = false;
    }

    if (inBlock) continue;
    newSource += line + Environment.NewLine;
}

var outputPath = "output/exp1.src";
System.Console.WriteLine("去除注释完成,创建新文件。");
using (var sWriter = new StreamWriter(outputPath))
{
    sWriter.Write(newSource);
}
System.Console.WriteLine("操作完成!文件路径:{0}", outputPath);
复制代码

结果测试

源文件
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
using namespace std;

int main()
{
    cout << '/';
    ifstream ifile; //建立文件流对象
    ofstream ofile;
    ifile.open("f:\\上机实验题\\C++\\ConsoleApplication2\\ConsoleApplication2\\源.cpp"); //打开F盘根目录下的fileIn.txt文件
    ofile.open("f:\\上机实验题\\C++\\ConsoleApplication2\\ConsoleApplication2\\源.obj");
    if (ifile.fail() || ofile.fail())
    { //测试打开操作是否成功
        cerr << "open file fail\n";
        return EXIT_FAILURE;
        /*返回值EXIT_FAILURE(在cstdlib库中定义),用于向操作系统报*
    告打开文件失败*/
    }
    char ch;
    ch = ifile.get(); //进行读写操作
    while (!ifile.eof())
    {
        if (ch == 34)
        {                   //双引号中若出现“//”,双引号中的字符不消除
            char temp = ch; //第一个双引号
            ofile.put(ch);
            ch = ifile.get();
            while (!ifile.eof())
            {
                if (ch != temp)
                { //寻找下一个双引号
                    ofile.put(ch);
                    ch = ifile.get();
                }
                else
                {
                    ofile.put(ch);
                    break;
                }
            }
            ch = ifile.get();
            continue; //双引号情况结束,重新新一轮判断
        }
        if (ch == 47)
        { //出现第一个斜杠
            char temp2 = ch;
            ch = ifile.get();
            if (ch == 47)
            { //单行注释情况
                ch = ifile.get();
                while (!(ch == '\n'))
                    ch = ifile.get();
            }
            else if (ch == '*')
            { //多行注释情况
                while (1)
                {
                    ch = ifile.get();
                    while (!(ch == '*'))
                        ch = ifile.get();
                    ch = ifile.get();
                    if (ch == 47)
                        break;
                }
                ch = ifile.get();
            }
            else
            {
                ofile.put(temp2); //temp2保存第一个斜杠,当上述两种情况都没有时,将此斜杠输出
            }
            //ch = ifile.get();
        }
        //cout << ch << endl;
        ofile.put(ch);    //将字符写入文件流对象中
        ch = ifile.get(); //从输入文件对象流中读取一个字符
    }
    ifile.close(); //关闭文件
    ofile.close();
    cout << "/*ret/rtr";
    system("pause");
    return 0;
}
复制代码
处理后的结果
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
using namespace std;
int main()
{
    cout << '/';
    ifstream ifile; 
    ofstream ofile;
    ifile.open("f:\\上机实验题\\C++\\ConsoleApplication2\\ConsoleApplication2\\源.cpp"); 
    ofile.open("f:\\上机实验题\\C++\\ConsoleApplication2\\ConsoleApplication2\\源.obj");
    if (ifile.fail() || ofile.fail())
    { 
        cerr << "open file fail\n";
        return EXIT_FAILURE;
    }
    char ch;
    ch = ifile.get(); 
    while (!ifile.eof())
    {
        if (ch == 34)
        {                   
            char temp = ch; 
            ofile.put(ch);
            ch = ifile.get();
            while (!ifile.eof())
            {
                if (ch != temp)
                { 
                    ofile.put(ch);
                    ch = ifile.get();
                }
                else
                {
                    ofile.put(ch);
                    break;
                }
            }
            ch = ifile.get();
            continue; 
        }
        if (ch == 47)
        { 
            char temp2 = ch;
            ch = ifile.get();
            if (ch == 47)
            { 
                ch = ifile.get();
                while (!(ch == '\n'))
                    ch = ifile.get();
            }
            else if (ch == '*')
            { 
                while (1)
                {
                    ch = ifile.get();
                    while (!(ch == '*'))
                        ch = ifile.get();
                    ch = ifile.get();
                    if (ch == 47)
                        break;
                }
                ch = ifile.get();
            }
            else
            {
                ofile.put(temp2); 
            }
        }
        ofile.put(ch);    
        ch = ifile.get(); 
    }
    ifile.close(); 
    ofile.close();
    cout << "/*ret/rtr";
    system("pause");
    return 0;
}
复制代码

完整代码

github.com/Deali-Axy/C…

参考资料:

欢迎与我交流

转载于:https://juejin.im/post/5cd6337ee51d453ae54a2073

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的去除多行注释的示例代码(使用C语言编写): ```c #include <stdio.h> void remove_comments(FILE* input_file, FILE* output_file) { int c, prev_c; int in_comment = 0; while ((c = fgetc(input_file)) != EOF) { if (in_comment) { // 如果当前在注释,则判断是否遇到了注释结束符号 if (prev_c == '*' && c == '/') { in_comment = 0; } } else { // 如果当前不在注释,则判断是否遇到了注释开始符号 if (prev_c == '/' && c == '*') { in_comment = 1; } else { // 如果当前不在注释且不是注释符号,则写入输出文件 fputc(prev_c, output_file); } } prev_c = c; } // 写入最后一个字符 fputc(prev_c, output_file); } int main(int argc, char* argv[]) { if (argc != 3) { printf("Usage: %s input_file output_file\n", argv[0]); return 1; } FILE* input_file = fopen(argv[1], "r"); if (input_file == NULL) { printf("Cannot open input file %s\n", argv[1]); return 1; } FILE* output_file = fopen(argv[2], "w"); if (output_file == NULL) { fclose(input_file); printf("Cannot open output file %s\n", argv[2]); return 1; } remove_comments(input_file, output_file); fclose(input_file); fclose(output_file); return 0; } ``` 以上代码使用了一个 `in_comment` 变量来表示当前是否在多行注释,同时使用 `prev_c` 变量来记录上一个字符。在遍历输入文件时,如果当前在注释,则判断是否遇到了注释结束符号;如果当前不在注释,则判断是否遇到了注释开始符号。如果当前不在注释且不是注释符号,则将上一个字符写入输出文件。 你可以根据需要对代码进行修改和优化,例如增加错误处理、优化读写文件的方式等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值