编译原理实验之词法分析

能识别小数,科学记数法表示的数。

不多解释,代码先上:

#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <fstream>
#include <map>
#include <cstdlib>
#include <cmath>
using namespace std;
const int maxn = 1002;
const int n_key = 40;
const int n_oper = 21;

char c;

string key_word[n_key] = {"auto", "enum", "restrict", "unsigned", "break",
                    "extern", "return", "void", "case", "float",
                    "short", "volatile", "char", "for", "signed",
                    "while", "const", "goto", "sizeof", "_Bool",
                    "continue", "if", "static", "_Complex", "default",
                    "inline", "struct", "_Imaginary", "do", "int",
                    "switch", "double", "long", "typedef", "else",
                    "register", "union", "main", "scanf", "printf"
};

string oper[] = {"+", "-", "*", "/", "^",
                "<", ">", "++", "--", "==",
                "*=", "/=", ">=", "<=", "<<",
                ">>", ">>=", "<<=", "%", "&",
                "^"
};

char bound[] = {',', ';', '(', ')', '[', ']', '{', '}'};

struct Word{                //词结构体
    int id;
    string value;
};

struct Num{
    int id;
    int vi;
    double vd;
};
Num n[maxn];        //数字
Word w[maxn];       //词
map<string, int> m;    //标识符
int f = 0, ff = 0;

bool is_oper(string s){
    for(int i=0; i<n_oper; i++) if(s == oper[i]) return true;
    return false;
}

bool is_bound(char c){
    for(int i=0; i<sizeof(bound); i++) if(c == bound[i]) return true;
    return false;
}

bool is_key(string s){
    for(int i=0; i<n_key; i++) if(s == key_word[i]) return true;
    return false;
}

int stoi(string s){                         //get int
    int ans = 0;
    for(int i=0; i<s.size(); i++) ans = ans * 10 + s[i] - '0';
    return ans;
}

double stof(string s){                      //get double
    long long ans = 0;
    int fd = -1, fe = -1;
    for(int i=0; i<s.size(); i++){
        if(s[i] == '.'){
            fd = i;
            continue;
        }
        if(s[i] == 'e'){
            fe = i;
            continue;
        }
        ans = ans * 10 + s[i] - '0';
    }
    if(fd != -1 && fe == -1) return double(ans)/(pow(10, s.size() - fd - 1));
    else if(fd == -1 && fe != -1){
        long long temp = ans % (long long)pow(10, s.size() - fe - 1);     //得到e后的数字
        ans /= pow(10, s.size() - fe - 1);                          //得到e前的数字
        return double(ans*pow(10, temp));
    }
    else{
        long long temp = ans % (long long)pow(10, s.size() - fe - 1);     //得到e后的数字
        cout<<ans<<" "<<s.size() - fe - 1<<" "<<temp<<endl;
        ans /= pow(10, s.size() - fe - 1);                                //得到e前的数字
        cout<<ans<<endl;
        long long tt = (s.size() - fd - 1) - (s.size() - fe - 1) - 1;     //得到.后的数字
        cout<<tt<<endl;
        return (double)ans/pow(10, tt) * (pow(10, temp));
    }
}

void getword(char filename[]){
    freopen(filename, "r", stdin);              //重定向

    string str = "";
    int flag, is_end;
    is_end = scanf("%c", &c);
    while(is_end != EOF){
        flag = 0;
        if(isspace(c)){
            while(isspace(c) && is_end != EOF){   //滤空格
                is_end = scanf("%c", &c);
            }
        }
        if(isalpha(c)){                         //以字母开头
            while(isalnum(c) || c == '_'){
                str += c;
                is_end = scanf("%c", &c);
            }
            w[++f].value = str;
            if(is_key(str)) w[f].id = 1;        //保留字
            else{
                w[f].id = 2;                     //标识符
                m[str] ++;
            }
            str = "";
            flag = 1;
        }
        if(isdigit(c)){                          //数字
            int fd = 0, fe = 0, fflag = 0;
            while(isdigit(c) || c == '.' || c == 'e'){
                if(c == '.') fd ++;
                if(c == 'e') fe ++;
                if(c == '.' && fe) fflag = 1;
                str += c;
                is_end = scanf("%c", &c);
            }
            if(str[str.size()-1] == '.' || str[str.size()-1] == 'e') fflag = 1;
            if(fflag){
                cout<<"错误-->不合法数字:"<<str<<endl;    //忽略不合法输入
            }
            else{
                if(!fd && !fe){
                    n[++ff].vi = stoi(str);
                    n[ff].id = 1;
                }
                else{
                    n[++ff].vd = stof(str);
                    n[ff].id = 2;
                }
                w[++f].id = 3;  w[f].value = str;
            }
            str = "";
            flag = 1;
        }
        if(is_bound(c)){            //界符
            str += c;
            w[++f].value = str;
            w[f].id = 4;

            is_end = scanf("%c", &c);
            str = "";
            flag = 1;
        }
        string ss = "";
        ss += c;
        if(is_oper(ss)){
            while(is_oper(ss)){
                str += c;
                is_end = scanf("%c", &c);
                ss += c;
            }
            if(is_oper(str)){
                w[++f].value = str;
                w[f].id = 5;
            }
            str = "";
            flag = 1;
        }
        if(!flag && is_end != EOF){
            str += c;
            w[++f].value = str;
            w[f].id = 6;

            is_end = scanf("%c", &c);
            str = "";
        }
    }
    freopen("CON", "r", stdin);           //关闭重定向,恢复标准
}

void to_file1(){                        //主表
    char filename[20];
    puts("请输入词法分析主表要保存到的地址:");
    scanf("%s", filename);
    fstream out;
    out.open(filename, ios::out);
    out<<"1.保留字   2.标识符   3.数字   4.界符   5.操作符   6.其他"<<endl<<endl;
    for(int i=1; i<=f; i++) out<<w[i].id<<"  "<<w[i].value<<endl;
    out.close();
}

void to_file2(){                        //标识符表
    ofstream out;
    char filename[20];
    puts("请输入词法分析标识符表要保存到的地址:");
    scanf("%s", filename);
    out.open(filename, ios::out);
    map<string, int>::iterator it;
    for(it=m.begin(); it!=m.end(); it++) out<<it->first<<endl;
    out.close();
}

void to_file3(){                        //数字表
    ofstream out;
    char filename[20];
    puts("请输入词法分析数字表要保存到的地址:");
    scanf("%s", filename);
    out.open(filename, ios::out);
    out<<"1.int   2.double"<<endl<<endl;
    for(int i=1; i<=ff; i++) out<<n[i].id<<"  "<<(n[i].id == 1 ? n[i].vi : n[i].vd)<<endl;
    out.close();
}

int main(){
    char filename[20];
    puts("请输入您要打开的文件地址:");
    scanf("%s", filename);

    getword(filename);

    to_file1();
    to_file2();
    to_file3();

    return 0;
}
时间: 2024-12-18 13:16:07

编译原理实验之词法分析的相关文章

哈工大软件学院编译原理实验1——词法分析

这次实验被"过来人"们定位非常easy,实验内容例如以下: ----------------------------------------------------------------------------------- 对例如以下工作进行展开描写叙述 (1) 给出语言的词法规则描写叙述 · 标识符.keyword.整常数.字符常数.浮点常数 · 单界符:+,-,×,;,- · 双界符:/*,:=,>=,<=,!=,- · 凝视 (2) 针对这样的单词的状态转换图和程

编译原理实验代码(词法分析,语法分析,中间代码生成)

花了一天写出的程序没有顾及很多层面,但对于理解基本的实验道理和交上实验还是有点帮助的.代码实现了基于有限自动机的词法分析,采用递归下降分析法和EBNF文法实现语法分析并生成中间代码. lexAnalysis.h /* * lexAnalysis.h * * Created on: 2014-12-2 * Author: liuqiushan */ #ifndef LEXANALYSIS_H_ #define LEXANALYSIS_H_ #include <stdio.h> #include

Java 实现《编译原理》简单词法分析功能

Java 实现<编译原理>简单词法分析功能 简易词法分析功能 要求及功能 (1)读取一个 txt 程序文件(最后的 # 作为结束标志,不可省去) { int a, b; a = 10; if(a>=1){ b = a + 20; } } (2)词法识别分析表 单词类别|单词自身值|内部编码 -|-|- 关键字| int.for.while.do.return.break.continue| 1 标识符| 除关键字外的以字母开头,后跟字母.数字的字符序列| 2 常数| 无符号整型数| 3

编译原理 实验3 语法分析

语法分析 一. 实验目的 算术表达式的文法可以是(你可以根据需要适当改变): E→E+E|E-E|E*E|E/E|(E)|i 根据算符优先分析法,将表达式进行语法分析,判断一个表达式是否正确. 二. 实验环境 操作系统:window xp 编写环境:visual c++ 编写语言:c语言 三. 实验内容 程序输入/输出示例: 如参考C语言的运算符.输入如下表达式(以分号为结束)和输出结果: (1)10; 输出:正确 (2)1+2; 输出:正确 (3)(1+2)/3+4-(5+6/7); 输出:正

吉首大学_编译原理实验题_基于预測方法的语法分析程序的设计【通过代码】

一.实验要求 实验二 基于预測方法的语法分析程序的设计 一.实验目的 了解预測分析器的基本构成及用自顶向下的预測法对表达式进行语法分析的方法,掌握预測语法分析程序的手工构造方法. 二.实验内容 1.了解编译程序的基于预測方法的语法分析过程. 2.依据预測分析原理设计一个基于预測方法的语法分析程序. 三.实验要求 对给定文法G[S]: S->AT       A->BU     T->+AT|$      U->*BU|$    B->(S)|m 当中,$表示空串. 1.推断上

编译原理实验二:LL(1)语法分析器

一.实验要求 不得不想吐槽一下编译原理的实验代码量实在是太大了,是编译原理撑起了我大学四年的代码量... 这次实验比上次要复杂得多,涵盖的功能也更多了,我觉得这次实验主要的难点有两个(其实都是难点...): 1. 提取左公因子或消除左递归(实现了消除左递归) 2. 递归求First集和Follow集 其它的只要按照课本上的步骤顺序写下来就好(但是代码量超多...),下面我贴出实验的一些关键代码和算法思想. 二.基于预测分析表法的语法分析 2.1 代码结构 2.1.1  Grammar类    功

编译原理 实验1 PL/0语言词法分析

PL/0语言词法分析 一. 实验目的 通过完成词法分析程序,了解词法分析的过程.编制一个读单词程序,对PL/0语言进行词法分析,把输入的字符串形式的源程序分割成一个个单词符号,即基本保留字.标识符.常数.运算符.界符五大类. 二. 实验环境 操作系统:window xp 编写环境:visual c++ .c-free.turbo c 编写语言:c语言 分析语言:PL/0 三. 实验内容 对PL/0语言进行词法分析,把输入的字符串形式的源程序分割成一个个单词符号,其词法描述如下: (1) 关键字:

编译原理 - 实验三 - 递归下降语法分析器的调试及扩展

一. 语法分析介绍 语法分析是编译过程的核心部分,它的主要任务是按照程序语言的语法规则,从由词法分析输出的源程序符号串中识别出各类语法成分,同时进行语法检查,为语义分析和代码生成做准备.执行语法分析任务的程序叫语法分析程序或语法分析器. 二. 所实现的语义分析和代码生成程序能处理什么语句 (1)简单变量的声明语句 (2)表达式语句 (3)if语句. (4)while语句 (5)for语句 (6)write语句 (7)read语句 (8)do语句. (9)处理过程调用和返回 三.实验过程 ①用VC

编译原理小作业词法分析程序

词法分析程序所参照的编码如70页表3.3 (<编译技术>张莉等著.--北京:高等教育出版社,2016.9.ISBN: 978-7-04-046317-0) 用Java语言实现如下: 1 import java.io.IOException; 2 import java.util.Arrays; 3 import java.util.HashMap; 4 import java.util.Map; 5 6 class Code{ 7 public static final int BEGINSY