kN_编译原理_2


大学期间的笔记补全。编译原理内容太多分几次。
课本《编译原理》第三版,陈火旺等编著。
笔记总目录:
一、引论
二、高级语言及其语法描述
三、词法分析
四、语法分析——自上而下分析
五、语法分析——自下而上分析
六、属性文法和语法制导翻译
七、语义分析和中间代码生成
八、优化
九、目标代码生成


四、语法分析——自上而下分析

不是正规文法是画不出来有限自动机的。语法一般都不是正规文法(是上下文无关文法)。

4.1 语法分析器的功能

  1. 语法分析的任务:对任一给定w ∈ V_T^*,判断 w ∈ L(G)?

  2. 语法分析器:按照产生式规则,做识别 w 的工作。

  3. 语法分析方法:

    • 自上(顶)而下分析:从文法的开始符号出发,反复使用各种产生式,寻找与输入符号匹配的最左推导。

      难点:一个终结符可能有多个候选式。

      exp: 若终结符 b 可以由非终结符 B,C,D 均能推导,则符号 b 的推导只能逐一实验,失败需要回头重新回溯推导。

    • 自下(底)而上分析:从输入符号串开始,逐步进行归约(最右推导的逆过程),直至归约到文法的开始符号。

4.2 自上而下分析的方法概述

  • 从文法的开始符号出发,向下推导,推出句子。

  • 对任何的输入串(单词符号),试图用一切可 能的办法, 从文法的开始符号出发,自上而下地为输入串建立一棵语法树,即为输入串寻找一个最左推导。

  • 回溯自上而下出现的问题:

    • 文法的左递归问题
      • 一个文法是含有左递归的,如果存在非终结符 PP ⇒^+Pα
      • 含有左递归的文法将使自上而下的分析过程陷入无限循环。
    • 虚假匹配问题
    • 回溯:回溯会引起时间和空间的大量消耗
    • 报告分析不成功时,难于知道输入串中出错的确切位置。

    实际上采用了一种穷尽一切可能的试探法,因此效率很低,代价很高。

4.3 LL(1)分析方法

  • 概念:从左(Left)到右扫描输入串,构造最左(Leftmost) 推导,分析时每步向前看一个(1)字符。

  • 目的:构造不带回溯的自上而下分析算法。

    • 左递归的消除
    • 消除回溯,提左因子
    • FIRST集合,FOLLOW集合
    • LL(1)分析条件
    • LL(1)分析方法
  • 消除左递归:

    左递归文法:

    一个文法含有下列形式的产生式时,

    • 直接递归

      • A→A\beta,\ \ \ \ A∈V_N, \beta ∈V^*
    • 间接递归

      • A→B\beta,B→A\alpha\ \ \ \ \ \ \ \ \ A,B∈V_N,\ \ \alpha,\beta ∈V^*

    称为左递归文法。

    如果一个文法是左递归时,则不能采用自顶向下分析法。

    • 直接左递归消除:

      直接左递归消除

    • 间接左递归消除算法:

      间接左递归消除算法

  • 回溯问题

    • 回溯原因

      若当前符号= a,下一步要展开A ,而 A → α_1|α_2|...|α_n ,怎样选择α_i ?

      (1)以 a 为头的 α_i 如果只有一个,则替换唯一;

      (2)若以 a 为头有多个 α_i 的,则替换不唯一,需要回溯,这是文法的问题,应该变换文法。

    • 文法的要求

      1. 不含左递归
      2. 对每个终结符的候选式,其任何推导的头符号(终结符)集合两两不相交
      3. A 的候选首符集中包含 ε,则 FIRST (A)∩ FOLLOW (A) = Φ
    • 回溯解决方法:提公因子法

      提取公共左因子,将文法改造成任何非终结符的所有候选首符集两两不相交。
      目的:消除歧义!不能由不同的推导路径得出同一个首符

      提公因子法

  • FIRST问题

    • 符号串α终结首符集 FIRST(α) 定义为:

      FIRST(α) = \lbrace a│ \alpha ⇒^* a… , a∈V_T \rbrace

      特别地,若 α ⇒^* ε,则规定 ε∈FIRST(α)

    • 计算FIRST(X)集:

      • X∈V_T, FIRST(X)=\lbrace X\rbrace
      • X∈V_N, FIRST(X)=\lbrace a|X→a…,a∈V_T\rbrace
      • X∈V_N, 且有产生式X →ε,则\lbrace ε\rbrace ∈ FIRST(X)
      • X∈V_N, 且有产生式X →Y_1Y_2…Y_n,且Y_1Y_2…Y_n∈ V_N
        • Y1 ,Y2 , … , Y_{i-1} ⇒ ε,则FIRST(Y_1)-\lbrace ε\rbrace, FIRST(Y_2)-\lbrace ε\rbraceFIRST(Y_{i-1})-\lbrace ε\rbrace, FIRST(Y_i)都包含在FIRST(X)
        • Y_i ⇒ ε(i=1,2…n),将\lbrace ε\rbrace并入FIRST(X)
  • FOLLOW问题

    • S 是文法 G 的开始符号,对 G 的任何非终结符 A,定义 A后继终结符号集为:

      FOLLOW(A) = \lbrace a│S ⇒^* … Aa… , a∈V_T \rbrace

    • 特别地,若 S ⇒^*…A,则规定#∈FOLLOW(A)

      FOLLOW(A)是所有句型中出现在紧接A之后的终结符或“#”。“#”可认为是一个句子的终止符。

  • 当非终结符 A 面临输入符号 a,且 a \notin FIRST(α_i) (对任意 i )时,如果 A 的某个候选首符集包含 ε(即 ε∈FIRST(A) ),那么,当 a∈FOLLOW(A) 时,就允许 A 自动匹配(即选用 A→ε 工作),否则,认为 a 的出现是一种语法错误。

  • LL(1)分析方法

    • LL(1)文法:

      如果文法G满足以下条件:

      (1)文法消除了左递归;

      (2)文法中每个非终结符A的各个产生式的候选首符集两两不相交,即:若A→α_1│α_2│… │α_n,则FIRST(α_i)∩FIRST(α_j) = Φ,(i ≠ j)

      (3)对文法中的每个非终结符 A,若它存在某个候选首符集中包含 ε,则 FIRST(A)∩ FOLLOW(A) = Φ

      则称该文法 GLL(1) 文法。

    • 对一个 LL (1)文法,可以对某个输入串进行有效的无回溯的自上而下分析。

    • 设面临的输入符号为 a ,要用非终结符 A 进行匹配,且 A→α_1│α_2│… │α_n ,则可如下分析:

      1. a∈FIRST (α_i) ,则指派 α_i 执行匹配任务;
      2. 否则
        • ε∈FIRST(A) ,且 a∈FOLLOW (A),则让 Aε 自动匹配;
        • 否则,a 的出现是一种语法错误。

4.4 分析方法:递归下降分析程序

  1. 条件:满足上述 LL(1) 文法的条件

  2. 构成

    • 一组递归过程
    • 每个递归过程对应 G 的一个非终结符
  3. 基本思想

    从文法开始符号出发,在语法规则(文法产生式)的支配下进行语法分析。逐个扫描源程序中的字符(单词符号),根据文法和当前输入字符分析到下一个语法成分 A 时,便调用识别和分析A的子程序(或其自身),如此继续下去。

  4. 程序形式


    程序形式_1

    程序形式_2

4.5 分析方法:预测分析程序

  1. 递归下降分析器的局限性:需要具有能够实现递归过程的语言和编译系统

  2. 预测分析程序:使用一个分析表和符号栈进行联合控制,是实现LL(1)分析的另一种有效方法。

  3. 程序流程:


    预测分析程序流程

LL(1)分析表M,行为非终结符,列为终结符,每一个M[A,a]表示非终结符A应该用什么产生式得出以a打头的表达式(若M[A,a]为空表示无法产生,报错)。


LL(1)分析表构造算法

五、语法分析——自下而上分析

自下而上分析法就是从输入串开始,逐步进行“归约”,直至归约到文法的开始符号。

从语法树的末端,步步向上“归约”,直到根结。

5.1 自下而上分析基本问题

  1. 归约
    • 移进-归约法:使用一个符号栈,把输入符号逐一移进栈,当栈顶形成某个产生式右部时,则将栈顶的这一部分替换(归约)为该产生式的左部符号。
  2. 基本问题:
    • 如何找出或确定可规约串?
    • 对找出的可规约串替换为哪一个非终结符号?

5.2 规范规约

  1. 短语

    • G 是一个文法,S 是文法的开始符号,若 αβδ 是文法 G 的一个句型,如果有:

      S ⇒^* αAδA ⇒^+ β

      则称 β 是句型 αβδ 相对于非终结符 A短语。(多步规约)

      特别地,若A ⇒ β,则称 β 是句型 αβδ 关于产生式 A→β直接短语。 (一步规约)

    • 一个句型的最左直接短语称为句柄

      二义文法的句柄不止一个。

    从树的角度考虑:

    短语:句型语法树中每棵子树(某个结点连同它的所有子孙组成的树)的所有叶子结点从左到右排列起来形成一个相对于子树根的短语。

    直接短语:只有父子两代的子树形成的短语。

    句柄:语法树中最左那棵只有父子两代的子树形成的短语。

    概念举例

  2. 规范规约

    α 是文法 G 的一个句子,若序列α_n, α_{n-1}, …, α_0,满足:

    (1)α_n = α
    (2)α_0 = S
    (3)对任意 i0< i ≤n , α_{i-1} 是从 α_i 将句柄替换成相应产生左部符号而得到的

    则称该序列是一个规范归约。

  3. 符号栈的使用:

    实现移进-归约分析的一个方便途径是用一个栈和一个输入缓冲区,用#表示栈底和输入的结束。


    符号栈
  4. 语法分析的操作

    • 移进:下一输入符号移进栈顶,读头后移;
    • 归约:检查栈顶若干个符号能否进行归约,若能,就以产生式左部替代该符号串,同时输出产生式编号;
    • 接收:移进-归约的结局是栈内只剩下栈底符号和文法开始符号,读头也指向语句的结束符;
    • 出错:发现了一个语法错误,调用出错处理程序。

5.3 算符优先分析方法

算符优先分析法是自下而上进行句型归约的一种分析方法。

定义终结符(即: 算符)的优先关系,按终结符 (算符)的优先关系控制自下而上语法分析过程(寻找“可归约串”和进行归约)。

不是规范归约,但分析速度快,适于表达式的语法分析。

  1. 算符文法

    一个文法,如果它的任一产生式右部都不含两个相继(并列)的非终结符,即不含如下形式的产生式右部:

    … QR … , Q, R ∈ V_N

    则称该文法为算符文法。

  2. 算符优先关系

    • 优先运算符

      任何两个可能相继出现的终结符 ab (它们之间可能插有一个非终结符)的优先关系:

      • a < b a 的优先级低于 b
      • a = b a 的优先级等于 b
      • a > b a 的优先级高于 b

      注:这三种关系不同于数学中的 <,=,> 关系。在以上场景中表示有产生式...ab...… aQb…

    • 算符优先关系

      G 为算符文法且不含 ε-产生式,a, b∈ V_T, 算符间的优先关系定义为:

      • a=b 当且仅当 G 含有产生式 P →… ab…P →… aQb…
      • a < b 当且仅当 G 含有产生式 P →… aR …R ⇒ b…R ⇒ Qb…
      • a > b 当且仅当 G 含有产生式 P →… Rb…R ⇒ … aR ⇒ … aQ

      生成树中,节点越深(层数越大,越偏向叶节点),算符的优先级越大。

  3. 算符优先文法

    如果一个算符文法 G 中的任何终结符对 (a, b) 至多满足下述关系之一:

    a=ba < ba > b

    则称 G 为算符优先文法。

  4. 优先关系表的构造

    • FIRSTVT(P)和LASTVT(P)

      P∈V_N ,定义 :

      FIRSTVT (P) = \lbrace a│P⇒a …P⇒Qa … , a ∈V_T , Q ∈V_N \rbrace

      LASTVT (P) =\lbrace a│P⇒… aP ⇒… aQ , a ∈V_T , Q∈V_N \rbrace

    • 构造

      • FIRSTVT (P) 构造

        规则1: 若 P→a …P→Qa … , 则 a ∈FIRSTVT(P);

        规则2: 若 a ∈FIRSTVT(Q) , 且 P→Q … , 则 a ∈FIRSTVT(P)

      • LASTVT (P) 构造

        规则1: 若 P→ … aP→ … aQ , 则 a ∈LASTVT(P);

        规则2: 若 a ∈LASTVT(Q) , 且 P→ … Q , 则 a ∈LASTVT(P)

        布尔矩阵与符号栈
  5. 算符优先分析算法

    • 将输入串依此逐个存入符号栈 S 中,直到符号栈顶元素 S_k 与下一个待输入的符号 a 有优先关系 S_k>a为止;

    • 至此,最左素短语尾符号 S_k 已在符号栈 S 的栈顶,由此往前在栈中找最左素短语的头符号 S_{j+1},直到找到第一个 < 为止;

    • 已找到最左素短语 S_{j+1}…S_k,将其归约为某个非终结符 N 及做相应的语义处理。

      最左素短语:在最左侧的,不包含更小短语的短语。在算符优先分析方法中,最左素短语一定要包含算符

      素短语的概念:它是个短语,并且至少含有一个终结符,并且,除它自身之外不再含任何更小的素短语,所谓最左素短语就是处于句型最左边的素短语。

      分析过程
      • 在算法的工作过程中,若出现 j 减1后的值小于等于0时,则意味着输入串有错。在正确的情况下,算法工作完毕时,符号栈 S 应呈现:# N #。
      • 由于非终结符对归约没有影响,因此,非终结符根本可以不进符号栈 S

      概念辨析:

      最左素短语:只关注算符(终结符),所有的非终结符都记为N,终结符规约为非终结符时也一律规约为N。最左素短语一定会出现在产生式右侧,但是会忽略所有非终结符的符号,一律视为N。

      句柄最左直接短语):

      直接短语:只有父子两代的子树形成的短语。

      算符分析法中规约的目标是:寻找最左素短语,逐步规约

5.4 LR分析法

  1. LR分析表举例


    表达式

    LR分析表

    根据LR分析表的分析过程需要两个栈,一个状态栈存状态,一个数据栈存算符和非终结符。

    • s5: 指shift 5,将指针所指的符号压入数据栈,将5压入状态栈。

    • r6: 指reduce 6,将当前数据栈中的符号按照第6个产生式规约(此例中为F->i)。经过规约操作之后,需要将数据栈栈顶弹出,将数据栈栈顶的规约结果压栈,同时将状态栈栈顶状态弹出

    • 1: 指状态迁移1,如状态栈栈顶为旧状态(比如(0,E)=1,旧状态为0),将旧状态弹出,压入新状态为栈顶。

    分析流程,状态栈压0,数据栈压#。将指针指向的第一个符号压入数据栈,根据状态栈栈顶(0)跟数据栈栈顶找出对应分析表中的内容并执行相应操作,循环判断直到对应表中内容为acc(成功)或空(失败)。


    分析过程
  2. LR分析法

    • 在自下而上的语法分析中,算符优先分析算法只适用于算符优先文法,还有很大一类上下文无关文法可以用LR分析法分析。

    • LR分析法中的L表示从左向右扫描输入串, R表示构造最右推导的逆。LR分析法是严格的规范规约。

    • 不足:LR分析法手工构造分析程序工作量相当大。

    • 总控程序: 所有的LR分析器相同

    • 分析表: 是自动生成语法分析器的关键

      • LR (0) 表:基础、有局限性
      • SLR表:简单LR表,实用
      • 规范LR表:能力强、代价大
      • LALR表:向前LR表,介于SLR和规范LR之间
    • 分析表的内容:LR分析器的核心是一张分析表

      • ACTION[s, a]:当状态s面临输入符号a时,应采取什么动作.

        每一项ACTION[s, a]所规定的四种动作:

        \1. 移进 把(s, a)的下一状态 和输入符号 推进栈,下一输入符号变成现行输入符号.

        \2. 归约 指用某产生式 进行归约. 假若 的长度为 , 归约动作是:去除栈顶 个项,使状态 变成栈顶状态,然后把 的下一状态 和文法符号 推进栈.

        \3. 接受 宣布分析成功,停止分析器工作.

        \4. 报错

      • GOTO[s, X]:状态s面对文法符号X时,下一状态是什么

      GOTO[s, X]定义了一个以文法符号为字母表的DFA

  3. LR文法

    • 对于一个文法,如果能够构造一张LR分析表, 使得它的每个入口均是唯一确定,则该文法称为LR文法。

      • 在进行自下而上分析时, 一旦栈顶形成句柄,即可归约。
    • LR(k)文法:对于一个文法,如果每步至多向前检查 k个输入符号,就能用LR分析器进行分析。则这个文法就称为LR(k)文法。

      • 大多数程序语言,符合LR(1)文法
  4. LR(0) 文法

    • k =0,即只要根据当前符号和历史信息进行分析,而无需展望。

    • 假若一个文法G的拓广文法G¢的活前缀识别自动机中的每个状态(项目集)不存在下述情况:

      (1) 既含移进项目又含归约项目;
      (2)含有多个归约项目

      则称G是一个LR(0)文法。

      即是:LR(0)文法规范族的每个项目集不包含任何冲突项目

    • 构造

      • 令每个项目集 I_k 的下标 k 作为分析器的状态。
      • 包含项目 S'→·S 的集合 I_k 的下标 k 为分析器的初态。
  5. SLR分析表

    LR(0)文法太简单,没有实用价值.

    假定一个LR(0)规范族中含有如下的一个项目集(状态) I={X→a·b\beta ,A→a·,B→a \ · }。FOLLOW(A)和FOLLOW(B)的交集为 \emptyset,且不包含b,那么,当状态I面临任何输入符号 a 时,可以

    • a=b ,则移进;
    • a\in FOLLOW(A),用产生式 A→a 进行归约;
    • a\in FOLLOW(B),用产生式 B→a 进行归约;
    • 此外,报错。

    SLR存在的问题:计算FOLLOW集合所得到的超前/后继符号集合可能大于实际能出现的超前/后继符号集。FOLLOW集合提供的信息太泛!

  6. 规范LR分析表

    https://blog.csdn.net/qq_40147863/article/details/93253171

    • 我们需要重新定义项目,使得每个项目都附带有 k 个终结符。每个项目的一般形式是 [A→a·\beta ,\ a_1a_2…a_k] ,这样的一个项目称为一个 LR(k) 项目。项目中的 a_1a_2…a_k 称为它的向前搜索符串(或展望串)。

    • 向前搜索符串仅对归约项目 [A→a·,\ a_1a_2…a_k] 有意义。对于任何移进或待约项目 [A→a·\beta,\ a_1a_2…a_k] , \beta \neq ε,搜索符串 a_1a_2…a_k 没有作用。

    • 动作ACTION和状态转换GOTO构造


      构造方法
    • 按上述算法构造的分析表,若不存在多重定义的入口(即,动作冲突)的情形,则称它是文法G的一张规范的LR(1)分析表。

    • 使用这种分析表的分析器叫做一个规范的LR分析器

    • 具有规范的LR(1)分析表的文法称为一个LR(1)文法。

    • LR(1)状态比SLR多:LR(0) \subset SLR \subset LR(1) \subset 无二义文法

    LR(0), SLR, LR(1)三种分析表仅仅在reduce操作有区别;

    其中LR(0),SLR分析表的构建方式相同;LR(1)不同。

    LR(0) & LR(1) 分析(分析表构成)算法的区别:

    • LR(0):


      LR(0)部分算法
    • LR(1):


      LR(1)部分算法
  1. LALR分析法

    • 研究LALR的原因规范LR分析表的状态数偏多
    • LALR特点
      • LALR和SLR的分析表有同样多的状态,比规范LR分析表要小得多
      • LALR的能力介于SLR和规范LR之间
      • LALR的能力在很多情况下已经够用
    • LALR分析表构造方法:通过合并规范LR(1)

在四种LR分析里,LR(0)对文法的要求最高(限制最多),LR(1)要求最低(限制最少)

  • LR(0)文法判定:

    如果文法对应的自动机中不存在移进-归约冲突和归约-归约冲突则为 LR(0)文法。换句话说LR(0)文法分析不能解决这两种冲突,所以范围最小。移进-归约冲突就是在同一个项集族中同时出现了可以移进的产生式和可以归约的产生式。归约-归约冲突类似。

  • SLR文法判定:

    SLR文法不存在归约-归约冲突,有可能存在移进-归约冲突,但是如果可以用 follow集解决则是 SLR文法。换句话说,SLR文法分析过程可以解决归约-归约冲突,但是不一定能解决移进-归约冲突。用 follow集来处理即出现移进-归约冲突的两条产生式,如果其 follow集相交为空则为 SLR文法,反之不是。

  • LALR文法判定:

    有个结论是合并同心集不会产生新的移进-归约冲突,但是会产生新的归约-归约冲突,如果没产生冲突就是 LALR 文法,反之不是。

  • LR(1)文法判定:

    因为 LR(1)文法的范围比较大,所以文法几乎都是 LR(1)的(只要LR(1)分析表没有冲突)。当合并同心集产生了归约-归约冲突时才属于LR(1)文法,而不属于其他文法。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351

推荐阅读更多精彩内容