• 用C++编写简单绘图语言的词法分析器——程序清单


      开发环境            Microsoft .NET Framework版本 2.0.50727
                          
    Microsoft Visual Studio 2005版本 8.0.50727.4
                          
    Microsoft Visual C++ 2005版本77983-009-0000007-41481
     1/********************************* scanner.h *********************************/
     2
     3#ifndef SCANNER_H
     4#pragma warning (disable:4996)                                // 屏蔽4996警告
     5#pragma warning (disable:4313)                                // 屏蔽4313警告
     6
     7#define SCANNER_H
     8
     9#include <string.h>
    10#include <stdio.h>
    11#include <stdlib.h>
    12#include <ctype.h>
    13#include <stdarg.h>
    14#include <math.h>
    15
    16enum Token_Type                                                /* 记号种类 */
    17{
    18    ORIGIN, SCALE, ROT, IS, TO, STEP, DRAW, FOR, FROM,            // 保留字
    19    T,                                                            // 参数
    20    SEMICO, L_BRACKET, R_BRACKET, COMMA,                        // 分隔符号
    21    PLUS, MINUS, MUL, DIV, POWER,                                // 运算符
    22    FUNC,                                                        // 函数
    23    CONST_ID,                                                    // 常数
    24    NONTOKEN,                                                    // 空记号
    25    ERRTOKEN                                                    // 出错记号
    26}
    ;
    27
    28typedef double (*MathFuncPtr)(double);                        /* 函数指针类型 */
    29
    30struct Token                                                /* 记号与符号表结构 */
    31{
    32    Token_Type type;                                            // 记号的类别
    33    char *lexeme;                                                // 构成记号的字符串
    34    double value;                                                // 若为常数,则是常数的值
    35    MathFuncPtr FuncPtr;                                        // 若为函数,则是函数的指针
    36}
    ;
    37
    38static Token TokenTab[] = {                                    /* 符号表内容 */
    39    {CONST_ID,    "PI",        3.1415926,    0   },
    40    {CONST_ID,    "E",        2.71828,    0   },
    41    {T,            "T",        0.0,        0   },
    42    {FUNC,        "SIN",        0.0,        sin },
    43    {FUNC,        "COS",        0.0,        cos },
    44    {FUNC,        "TAN",        0.0,        tan },
    45    {FUNC,        "LN",        0.0,        log },
    46    {FUNC,        "EXP",        0.0,        exp },
    47    {FUNC,        "SQRT",        0.0,        sqrt},
    48    {ORIGIN,    "ORIGIN",    0.0,        0   },
    49    {SCALE,        "SCALE",    0.0,        0   },
    50    {ROT,        "ROT",        0.0,        0   },
    51    {IS,        "IS",        0.0,        0   },
    52    {FOR,        "FOR",        0.0,        0   },
    53    {FROM,        "FROM",        0.0,        0   },
    54    {TO,        "TO",        0.0,        0   },
    55    {STEP,        "STEP",        0.0,        0   },
    56    {DRAW,        "DRAW",        0.0,        0   }
    57}
    ;
    58
    59extern unsigned int LineNo;                                    /* 跟踪记号所在源文件行号 */
    60extern int InitScanner(const char *);                        /* 初始化词法分析器 */
    61extern Token GetToken();                                    /* 获取记号 */
    62extern void CloseScanner();                                    /* 关闭词法分析器 */
    63
    64#endif

      1/********************************* scanner.cpp *********************************/
      2
      3#include "scanner.h"
      4
      5#define TOKEN_LEN 100                                        // 记号最大长度
      6
      7unsigned int LineNo;                                        // 跟踪源文件行号
      8static FILE *InFile;                                        // 输入文件流
      9static char TokenBuffer[TOKEN_LEN];                            // 记号字符缓冲
     10
     11/* 初始化词法分析器 */
     12extern int InitScanner(const char *FileName)
     13{
     14    LineNo = 1;
     15    InFile = fopen(FileName, "r");
     16    return ((InFile != 0? 1 : 0);
     17}

     18
     19/* 关闭词法分析器 */
     20extern void CloseScanner()
     21{
     22    if(InFile != 0) fclose(InFile);
     23}

     24
     25/* 从输入源程序读入一个字符 */
     26static char GetChar()
     27{
     28    int Char = getc(InFile);
     29    return toupper(Char);
     30}

     31
     32/* 把预读的字符退回到输入源程序中 */
     33static void BackChar(char Char)
     34{
     35    if(Char != EOF) ungetc(Char, InFile);
     36}

     37
     38/* 加入字符到记号缓冲区 */
     39static void AddCharTokenString(char Char)
     40{
     41    int TokenLength = (int)strlen(TokenBuffer);
     42    if(TokenLength + 1 >= sizeof(TokenBuffer)) return;
     43    TokenBuffer[TokenLength] = Char;
     44    TokenBuffer[TokenLength + 1= '\0';
     45}

     46
     47/* 清空记号缓冲区 */
     48static void EmptyTokenString()
     49{
     50    memset(TokenBuffer, 0, TOKEN_LEN);
     51}

     52
     53/* 判断所给的字符串是否在符号表中 */
     54static Token JudgeKeyToken(const char *IDString)
     55{
     56    for(int loop = 0; loop < sizeof(TokenTab) / sizeof(sizeof(TokenTab[0])) / 6++loop)
     57                                /* 注意:需要" / 6",否则 TokenTab 中的元素个数扩大了 6 倍 */
     58    {
     59        if(strcmp(TokenTab[loop].lexeme, IDString) == 0return TokenTab[loop];
     60    }

     61    Token errortoken;
     62    memset(&errortoken, 0sizeof(Token));
     63    errortoken.type = ERRTOKEN;
     64    return errortoken;
     65}

     66
     67/* 获取一个记号 */
     68extern Token GetToken()
     69{
     70    Token token;
     71    int Char;
     72
     73    memset(&token, 0sizeof(Token));
     74    EmptyTokenString();
     75    token.lexeme = TokenBuffer;
     76    
     77    for(;;)                                                    // 过滤源程序中的空格、TAB、回车等,遇到文件结束符返回空记号
     78    {
     79        Char = GetChar();
     80        if(Char == EOF)
     81        {
     82            token.type = NONTOKEN;
     83            return token;
     84        }

     85        if(Char == '\n') LineNo++;
     86        if(!isspace(Char)) break;
     87    }

     88
     89    AddCharTokenString(Char);                                // 若不是空格、TAB、回车、文件结束符等,则先加入到记号的字符缓冲区中
     90
     91    if(isalpha(Char))                                        // 若Char是A-Za-z,则一定是函数、关键字、PI、E等
     92    {
     93        for(;;)
     94        {
     95            Char = GetChar();
     96            if(isalnum(Char)) AddCharTokenString(Char);
     97            else break;
     98        }

     99        BackChar(Char);
    100        token = JudgeKeyToken(TokenBuffer);
    101        token.lexeme = TokenBuffer;
    102        return token;
    103    }

    104    else if(isdigit(Char))                                    // 若是一个数字,则一定是常量
    105    {
    106        for(;;)
    107        {
    108            Char = GetChar();
    109            if(isdigit(Char)) AddCharTokenString(Char);
    110            else break;
    111        }

    112        if(Char == '.')
    113        {
    114            AddCharTokenString(Char);
    115            for(;;)
    116            {
    117                Char = GetChar();
    118                if(isdigit(Char)) AddCharTokenString(Char);
    119                else break;
    120            }

    121        }

    122        BackChar(Char);
    123        token.type = CONST_ID;
    124        token.value = atof(TokenBuffer);
    125        
    126        return token;
    127    }

    128    else
    129    {
    130        switch(Char)
    131        {
    132        case ';' : token.type = SEMICO; break;
    133        case '(' : token.type = L_BRACKET; break;
    134        case ')' : token.type = R_BRACKET; break;
    135        case ',' : token.type = COMMA; break;
    136        case '+' : token.type = PLUS; break;
    137        case '-' : 
    138            Char = GetChar();
    139            if(Char == '-')
    140            {
    141                while(Char != '\n' && Char != EOF) Char = GetChar();
    142                BackChar(Char);
    143                return GetToken();
    144            }

    145            else
    146            {
    147                BackChar(Char);
    148                token.type = MINUS;
    149                break;
    150            }

    151        case '/' : 
    152            Char = GetChar();
    153            if(Char == '/')
    154            {
    155                while(Char != '\n' && Char != EOF) Char = GetChar();
    156                BackChar(Char);
    157                return GetToken();
    158            }

    159            else
    160            {
    161                BackChar(Char);
    162                token.type = DIV;
    163                break;
    164            }

    165        case '*' :
    166            Char = GetChar();
    167            if(Char == '*')
    168            {
    169                token.type = POWER;
    170                AddCharTokenString(Char);                    
    171                break;
    172            }

    173            else
    174            {
    175                BackChar(Char);
    176                token.type = MUL;
    177                break;
    178            }

    179        default  : token.type = ERRTOKEN; break;
    180        }

    181    }

    182    return token;
    183}

     1/********************************* scannermain.cpp *********************************/
     2
     3#include "scanner.h"
     4
     5int main(int argc, char *argv[])
     6{
     7    Token token;
     8    if(!InitScanner("test.txt"))
     9    {
    10        printf("Open Source File Error !\n");
    11        return -1;
    12    }

    13    printf("记号类别      字符串     常数值         函数指针\n");
    14    printf("________________________________________________\n");
    15    while(1)
    16    {
    17        token = GetToken();
    18        if(token.type != NONTOKEN)
    19            printf("%4d, %12s, %12f, %12x\n", token.type, token.lexeme, token.value, token.FuncPtr);
    20        else break;
    21    }
    ;
    22    printf("________________________________________________\n");
    23    CloseScanner();
    24    return 0;
    25}
  • 相关阅读:
    火狐flash插件
    centos 安装php ide (eclipse + php 插件)
    编译器的工作过程
    php中调用mysql的存储过程和存储函数
    mysql 高性能
    存储过程/游标/mysql 函数
    php 生成二维码
    frameset,frame应用,常用于后台
    html5 meta头部设置
    CAReplicatorLayer复制Layer和动画, 实现神奇的效果
  • 原文地址:https://www.cnblogs.com/suyang/p/1123123.html
Copyright © 2020-2023  润新知