逻辑行计数
背景
有一个软件公司常常用一种不为人知的语言来开发程序,这个语言的特点如下:
- 有两种形式的字符串,一种为加单引号,另一种加双引号。单引号的字符串可以包含双引号,双引号的字符串也可以包含单引号。字符串不能分行,其中也不能包含同样的引号字符。
- 有两种注释方式:@字符为行注释,而双括号(())内的文本为块注释。
- 块注释不能嵌套,所有在块中的文本均被忽略。一个块可以包含几行文本。
- 注释不能出现在字符串内。
- 在块注释中的行注释字符和引号都是没有意义的。
- 注释行中的双括号和引号都是没有意义的。
- 程序的任何部分都不能出现“#”字符;即使在字符串或注释内。
- 分号用来终止语句和生命。每个不在注释或字符串中的分号都被作为程序逻辑行的结束。
可以用逻辑行数来粗略地评估程序的大小,即计算不在注释或字符串内的分号的个数。写一个程序读进去几组程序代码,对每组代码都输出逻辑行数和物理行数,并对未终止的注释块和字符串发出警告消息。
输入
输入包含一个或多个程序,以#表示每个程序终止,以##表示输入终止。
输出
对于包括未终止字符串的行,输出:“Unterminated string in line n.”,其中n换成行号。
如果该程序包括一个未终止的块注释,以如下格式输出一行:”Unterminated block comment at end of program.“
在错误信息之后,以如下格式输出一行:”Program x contains y logical lines and z physical lines.“。其中x、y和z用相应的数字代替。
用例:
输入:
((Block comment:))
"string";('another string;');@line comment
##
输出:
Program 1 contains 2 logical lines and 2 physical lines.
- 枚举各个符号起作用时的限制条件,单中有双,双中有单的情况可以忽略中间的引号。
- 换行时,未终止的字符串强行终止,之前的引号效果消失。行注释的效果也消失。块注释效果保留。
- 字符串中出现注释时,双括号及@将起效果。(题目中第四点?)
- asdasd#asdasd↵ ,asdasd#↵ ,#asdasd↵
;这三种情况,一和二中#前的字符不算到上一个程序的物理行,一和三中#后的字符计入下一程序的物理行内。(当回车前不是#时物理行++)
- 优先级? # > 注释 > 字符串 > 分号
- 关爱膀胱,做题前先清空内存,避免溢出。
AC代码:(非栈,内含大量标记)
#include<stdio.h>
int khmark = 0, dmark = 0, smark = 0, at_mark = 0,end_mark = 0, logic = 0, physics = 0, program = 1;
//块注释标记 双引号标记 单引号标记 @标记 输入结束标记 逻辑行 物理行 程序数
void strout() {
printf("Unterminated string in line %d.\n", physics);
}
void zsout() {
printf("Unterminated block comment at end of program.\n");
}
void programout() {
printf("Program %d contains %d logical lines and %d physical lines.\n", program, logic, physics);
program++; logic = 0; physics = 0; // 清理标记
khmark = 0; dmark = 0; smark = 0; at_mark = 0;
}
void sw(char ch)
{
char cht;
switch (ch)
{
case '\"': {
if((!at_mark)&&(!khmark)&&(!smark)) //注释中的字符串没用
dmark = dmark ^ 1; break;
}
case '\'': {
if ((!at_mark) && (!khmark)&&(!dmark)) //注释中的字符串没用
smark = smark ^ 1; break;
}
case '#': {
if (smark || dmark) {
strout(); dmark = 0; smark = 0;
}
if (khmark) zsout();
programout();
if (cht = getchar(), cht == '#')
end_mark = 1;
else
if (cht != '\n') sw(cht); //#后面的换行算不算?
break;
}
case '(': {
cht = getchar();
if (cht == '(' && (!at_mark) && (!khmark)) //不在块注释和行注释中
khmark = 1;
else sw(cht);
break;
}
case')': {
cht = getchar();
if (cht == ')' && (!at_mark) && khmark)//不在行注释 前有块注释
khmark = 0;
else sw(cht);
break;
}
case'@': {
if ((!khmark)) at_mark = 1; //不在块注释
break;
}
case'\n': {
physics++;
if (at_mark) at_mark = 0; //取消行注释影响
if (dmark || smark) { //未终止的字符串 换行之后取消
strout(); dmark = 0; smark = 0;
}
break;
}
case';': {
if((!khmark)&&(!at_mark)&&(!smark)&&(!dmark))
logic++; //块注释 行注释 字符串里面的都没用
}
default:
break;
}
}
void main()
{
char ch;
while (1) {
if (end_mark) break;
ch = getchar();
sw(ch);
}
}