#P9800. [NERC2018] JS Minification

[NERC2018] JS Minification

题目背景

翻译自 NERC 2018 J 题。

题目描述

你有一个程序,其中每行包含 00 个或多个可以用空格分隔的标记,你需要将其按下列方法“压行”。

  • 在每一行中,如果存在 # 开头的部分,说明这是一个注释,其与其同一行后面的东西一起不被执行。

  • 通过重复跳过空格并从当前解析位置开始查找可能最长的标识符,将每一行从左到右解析为标识符序列,从而将源代码转换为标识符序列。下面列出了所有可能的标识符:

  • 保留标识符:缩小过程中应保留的任何类型的运算符、分隔符、文字、保留字或库函数的名称。保留标记是不包含 # 的非空格 ASCII 字符的固定字符串。
  • 数字标识符:有数字组成的一连串数字字符串。
  • 单词标识符:由以下集合中的一系列字符组成:小写字母、大写字母、数字、_$ 且不以数字开头。

请注意,在压缩过程中,满足数字或单词定义,但出现在保留标记列表中的最长字符序列被视为保留标识符。

在压缩过程中,使用以下算法以系统的方式重命名单词:

  • 定义 ss 为若干个由小写字母组成的字符串按长度为第一关键词,字典序为第二关键词进行排序后的序列。

  • 将标识符序列中遇到的第一个单词重命名为目标单词列表中的第一个词,并将标识符顺序中出现的所有相同单词重命名成第一个词。然后将标识符序列中遇到的第二个新词重命名为目标单词列表中的第二单词,依此类推。

此外,你可以删除原本某些不必要的空格与换行符。但是注意,你删除后并不可以使原本不是标识符的某些字符串变成了标识符,或是原本是标识符的变成了不是标识符的。

输入格式

输入的第一行包含一个整数 n (1n40)n \ (1 \leq n \leq 40),代表标识符的数量。

输入的第二行包含由空格分隔的保留标识符的列表,该列表中没有重复,长度不小于 11,不大于 2020

输入的第三行包含单个整数 m (1m40)m \ (1 \leq m \leq 40),代表输入代码中的行数。

接下来 mm 行一行一串代码(可能包含前导空格)。

输出格式

输出一行,是对输入代码进行压缩处理的结果。输出解析后的与具有相应重命名后的标识符序列,并且应包含尽可能少的空格。如果有多种方法,那请输出空格最少且长度最小的。

16
fun while return var { } ( ) , ; > = + ++ - --
9
fun fib(num) { # compute fibs
  var return_value = 1, prev = 0, temp;
  while (num > 0) {
    temp = return_value; return_value = return_value + prev;
    prev = temp;
    num--;
  }
  return return_value;
}

fun a(b){var c=1,d=0,e;while(b>0){e=c;c=c+d;d=e;b--;}return c;}

10
( ) + ++ : -> >> >>: b c)
2
($val1++ + +4 kb) >> :out
b-> + 10 >>: t # using >>: 

(a+++ +4c )>> :d b->+10>>:e

提示

保证数据范围 1n401 \leq n \leq 401m401 \leq m \leq 40