编译器设计1---编译器结构

本文详细介绍了编译器的一般结构,包括前端和后端的划分,重点讲解了词法分析器的工作原理和构造方法。通过实例展示了如何使用C#实现词法分析器,将字符流转化为记号流,同时提供了词法分析器的手工构造和自动生成两种方式的对比。
摘要由CSDN通过智能技术生成

PS:部分图片是中科大保健老师的课上截屏过来的

1.一般编译器的结构

在这里插入图片描述

简单来说一个编译器的设计其工程规模是十分庞大的,从字符序列到目标代码其中的每一次转变都需要一个模块的作用

2.编译器自顶向下阶段划分

如果将我们常用的编译器看成一个黑盒,不管内部的实现:
在这里插入图片描述
如果要看到更细节的地方:
在这里插入图片描述
源程序需要经过前端(front end)产生中间表示,再经过后端(back end)去产生目标代码。
可以看出:前端处理的是和源程序相关的属性,后端处理的是具体的体系结构和目标机相关的属性

2.1前端构造

语义分析器有时也成为类型检查器
在这里插入图片描述

2.1.1词法分析器

在这里插入图片描述
将字符流读取进来转换为记号流,字符流就是源代码字符串,记号流则是在程序中将字符串中每一个有意义的部分打上记号(Token)。
在这里插入图片描述
对于这些有穷的记号集合我们有能力用程序描述出来,可以将每一个记号看作一个结构体或者类,比如如果使用C#语言去描述:
首先需要枚举出所有可能的类型名称,使用类型和语义的结构体来描述一个记号

namespace HylicCompiler
{
    //描述类型
    enum DescirbeType{
        IF,     //if
        ELSE,   //else
        ELIF,   //elif
        LPAREN, //(
        RPAREN, //)
        IDENT,  //标识符
        GT,     // > 
        ASSIGN, // =
        STRING, //"xxxx"
        SEMICOLON,// ;
        INT        // 10
    }
    /// <summary>
    /// 记号结构体
    /// 如果是"hello world" 则T=STRING  lexeme="hello world"
    /// 如果是 if           则T=IF      lexeme=null
    /// 如果是 标识符x       则T=IDENT   lexeme="x"
    /// </summary>
    struct Token
    {
        DescirbeType T; //类型
        string lexeme;  //语义
    }
}

定义好记号后,词法分析器的任务就开始了,它会一个个的去读取字符串中有意义的字串,并转化为记号,从而字串流就变为了记号流.

2.1.2 词法分析器的构造方法

词法分析器的构造有两种方法:
方法1.手工构造,代码量大,相对复杂,容易出错。但是目前非常流行GCC,LLVM
方法2.声明好规则交给一种机器,它会帮你生成词法分析器。 快捷,代码量少,难以控制细节

尝试实现过的一个Stack计算机的paser

Token类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HylicCompiler
{

    //zen-code will be  composed with following element
    enum DescirbeType{
        IF,         // if
        ELSE,       // else
        ELIF,       // elif
        LPAREN,     // (
        RPAREN,     // )
        IDENT,      // identify
        GT,         // > 
        LT,         // <
        PLUS,       // +
        MINUS,      // -
        MULTIPLY,   // *
        DEVIDE,     // /
        ASSIGN,     // =
        STRING,     // "xxxx"
        SEMICOLON,  // ;
        INT,        // 10
        FLOAT,      // 10.12
    }
    /// <summary>
    /// 记号类
    /// 如果是"hello world" 则T=STRING  lexeme="hello world"
    /// 如果是 if           则T=IF      lexeme= null
    /// 如果是 标识符x       则T=IDENT   lexeme="x"
    /// </summary>
    class Token
    {
        public DescirbeType T; //类型
        public string lexeme;  //语义
        public Token(DescirbeType t,string lexeme) {
            this.T = t;
            this.lexeme = lexeme;
        }
        //For Debug
        public void PrintSelf()
        {
            if(lexeme!=null)
            {
                Console.WriteLine($"Type:{T.GetType()},Value:{lexeme}\n");
            }
            else
            {
                Console.WriteLine($"Type:{T.GetType()}\n");
            }
        }
    }
}
Lexer类
namespace HylicCompiler
{
    /// <summary>
    /// List possible situation correspond with each Type
    /// </summary>
    sealed class Possible
    {
        public static string DIGITAL = "1234567890";
    }
    /// <summary>
    /// 记录分析到的位置
    /// </summary>
    class Position
    {
        public int _index;      //指针位置
        public int _line;       //行号
        public int _column;     //列号
        public string _source;  //来源
        public string _txt;     //文本内容
        /// <summary>
        /// 初始化位置指针
        /// </summary>
        /// <param name="index">指针位置</param>
        /// <param name="line">行号</param>
        /// <param name="column">列号</param>
        /// <param name="source">字符序列来源</param>
        /// <param name="txt">文本类</param>
        public Position(int index,int line,int column,string source,string txt)
        {
            this._index = index;
            this._line = line;
            this._column = column;
            this._source = source;
            this._txt = txt;
        }
        /// <summary>
        /// 返回一份位置的副本
        /// </summary>
        /// <returns></returns>
        public Position GetDuplicate()
        {
            return new Position(this._index, this._line, this._column, this._source, this._txt);
        }

        /// <summary>
        /// 前向匹配
        /// </summary>
        /// <param name="current_char"></param>
        public void next(char current_char)
        {
            _index += 1;
            _column += 1;
            if (current_char == '\n')       //遇到换行符,列号清零 行号加一
            {
                _column = 0;
                _line += 1;
            }
        }
    }


    /// <summary>
    /// 词法分析器-Craft
    /// </summary>
    class Lexer
    {
        private string      _source;       //来源
        private string      _text;         //文本内容
        private Position    _pos;          //位置
        private char        _current_char; //当前字符
        private List<Token> tokens;
        public Lexer(string source,string text)
        {
            _source = source;
            _text = text;
            _pos = new Position(-1, 0, -1, source, text);
            _current_char =Char.MinValue;
            this.next();     // 0   0   0 
        }
        /// <summary>
        /// 前向
        /// </summary>
        public void next()
        {
            this._pos.next(this._current_char);
            if(_pos._index < _text.Length)
            {
                _current_char = _text[_pos._index];
            }
            else
            {
                _current_char = Char.MinValue;
            }
        }
        public void PrintSelf()
        {
            Console.WriteLine(tokens.Count);
            foreach(var t in tokens)
            {
                Console.Write($"[{t.T}  {t.lexeme}] ");
            }
            Console.Write(" \n");
        }

        /// <summary>
        /// Create Tokens From Code Text
        /// </summary>
        /// <param name="txt"></param>
        /// <returns>Tokens</returns>
        public List<Token> MakeTokens()
        {
            tokens = new List<Token>();
            Console.WriteLine(_text);
            while (_current_char!=Char.MinValue)
            {
                //pass if blank or tabs
                if(_current_char == ' ' || _current_char == '\t')
                {
                    this.next();
                } 
                // current char exist in "1234567890"  which means a Number(int or float) is coming
                else if (Possible.DIGITAL.Contains(_current_char))
                {
                    tokens.Add(this.MakeNumberToken());
                }
                else if(_current_char == '+')
                {
                    tokens.Add(new Token(DescirbeType.PLUS, null));
                    this.next();
                }
                else if(_current_char == '-')
                {
                    tokens.Add(new Token(DescirbeType.MINUS, null));
                    this.next();
                }
                else if(_current_char == '(')
                {
                    tokens.Add(new Token(DescirbeType.LPAREN, null));
                    this.next();
                }
                else if(_current_char == ')')
                {
                    tokens.Add(new Token(DescirbeType.RPAREN, null));
                    this.next();
                }
                else if (_current_char == '*')
                {
                    tokens.Add(new Token(DescirbeType.MULTIPLY, null));
                    this.next();
                }
                else if (_current_char == '/')
                {
                    tokens.Add(new Token(DescirbeType.DEVIDE, null));
                    this.next();
                }
                else
                {
                    //report error position and report
                    Position ErrPos = _pos.GetDuplicate();
                    char ErrChar = _current_char;
                    IllegalCharError illegalCharError = new IllegalCharError(ErrPos, ErrPos, $"Illegal Char:{ErrChar}");
                }
            }
            return tokens;
        }
        /// <summary>
        /// Coming A int or A float Number
        /// </summary>
        /// <returns>A number Token</returns>
        public Token MakeNumberToken()
        {
            string numstr = "";
            int dot_count = 0;
            //current char exist in "1234567890."
            while(_current_char != char.MinValue &&
                    _current_char!=' ' && 
                    (Possible.DIGITAL+'.').Contains(_current_char) )
            {
                //match dotnet
                if (_current_char == '.')
                {
                    //judge occurrence number of dot.
                    //invalide if More than one 
                    //add into numstr  if zero
                    if (dot_count == 1)
                        break;
                    dot_count += 1;
                    numstr += '.';
                }
                //match char
                else
                {
                    numstr += _current_char;
                }
                this.next();
            }

            //dot_count =0 ==> int
            if(dot_count == 0)
            {
                return new Token(DescirbeType.INT, numstr);
            }
            //dot_count =1 ==> float
            else
            {
                return new Token(DescirbeType.FLOAT, numstr);
            }

            return default(Token);
        }

    }
}

字符串流转化为记号流的效果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值