消除死代码


20

死代码坐在那里什么也没做,盯着我们知道它永远不会被执行……但是今天我们可以报仇了。

规格

输入将是多行字符串。

每行可以是一个赋值或一个表达式

分配

作业的形式为 <name> = number name是字母,下划线和数字的序列,但不能以数字开头。

变量可以被分配任意次。

表达

表达式的形式 <var_name OR number> <operation> <var_name OR number> ...

表达式可以是以下各项的任意组合:

  • 已经定义的变量
  • 基本算术运算符 +-*/
  • 数字(整数)

预期产量

您应该输出带有多余赋值的字符串,该赋值已删除,其后的任何表达式都不会使用这些赋值。请注意,如果在执行使用变量的表达式之前执行了对同一变量的附加分配,则分配也可以变得多余。

测试用例

a = 10
a * 3

a = 10
a * 3

foo = 8
2 - 1
a = 18

2 - 1

a = 10
a = 8
b = 4
ab = 72  
b / 6
b + 1

b = 4
b / 6
b + 1

a = 1
a = 2
a + 1

a = 2
a + 1

FooBar1 = 0
Fuz__ = 8
Fuz__ / 1

Fuz__ = 8
Fuz__ / 1

a = 1
a + 1
a = 2
a + 1

a = 1
a + 1
a = 2
a + 1

a = 1
1 / 5 * 8 + 4

1 / 5 * 8 + 4

a = 1
a + 1
a = 1
a + 1

a = 1
a + 1
a = 1
a + 1

a = 7
5 / a

a = 7
5 / a

1
如果您添加此特别困难的情况下:a = 1; a + 1; a = 1; a + 1;a = 1仅因为a先前已将其设置为相同的值(1),才能丢弃秒。
flodel

3
@flodel没有,没有必要看价值观
Caridorc

@flodel测试用例纳入
Caridorc

您应该添加一个测试用例,其中在表达式中使用变量,而不是将其用作表达式的第一个元素。作为表达式的最后一个成员尤其重要。
isaacg 2015年

@isaacg没有无效代码,var可能在任何地方,已添加测试用例
Caridorc

Answers:


9

PHP-197字节

该函数的工作原理是:以相反的顺序分析每一行,并逐行分析,并维护一组使用的变量。

  • 如果=一行中有一个相等的字符,则是一个赋值。
    • 如果使用了该变量,则分配是有用的,并且打印了该行,但是不再认为该变量已被使用。
    • 否则,什么都不做。
  • 否则,该行是一个表达式。我们在每个空格之后分割行,并将每个符号添加到使用的变量列表中。数字(1,,2…)和运算符(+,,-…)也将被添加,但是由于它们不是有效的变量名称,所以这不是问题。然后当然会打印该行。
function($c){$u=[];foreach(array_reverse(split('
',$c))as$l){if($p=strpos($l,'=')){if(!isset($u[$x=substr($l,0,$p-1)]))continue;
unset($u[$x]);}else$u+=array_flip(split(' ',$l));$f="
$l$f";}echo$f;}

这是非高尔夫版本:

function removeDeadCode($code)
{
    $usedVariables = [];
    $finalCode = '';

    foreach (array_reverse(explode("\n", $code)) as $line)
    {
        if ($equalPosition = strpos($line, '='))
        {
            $variable = substr($line, 0, $equalPosition - 1);
            if (isset($usedVariables[$variable]))
            {
                $finalCode = "\n" . $line . $finalCode;
                unset($usedVariables[$variable]);
            }
        }
        else
        {
            $usedVariables += array_flip(explode(' ', $line));
            $finalCode = "\n" . $line . $finalCode;
        }
    }

    echo $finalCode;
}

7

视网膜,45字节

m`^(\w+) =.*\n(?=((?!\b\1\b)[^!])*(^\1 =|\Z))
<empty>

出于计数目的,每行进入一个单独的文件(其中<empty>为空文件),并且\n应替换为实际的换行符(0x0A)。

假设字符串将始终以换行符结尾。

由于此正则表达式不使用任何.NET特定功能,因此可以在regex101上对其进行测试

这个想法很简单:删除所有赋值,我们可以从中找到(向前搜索)同一变量或字符串末尾的另一个赋值,而无需再次使用该变量。


6

Pyth,40个字节

eMf|!}K\=eT&Jf}+dhceTK++dYdPT!}KeJ_.__.z

似乎有点长。也许明天我可以保存一两个字节。

在线尝试:演示测试套件

说明:

_.__.z以相反的顺序给出输入行的所有后缀。例如,输入FooBar1 = 0; Fuz__ = 8; Fuz__ / 1给出列表:

[['Fuz__ / 1', 'Fuz__ = 8', 'FooBar1 = 0'], 
 ['Fuz__ / 1', 'Fuz__ = 8']
 ['Fuz__ / 1']]

然后,我筛选列表元素T,其中=不在T(expression)的最后一个元素或(assignment)中的最后一个元素T(其中包含变量名)是表达式。然后,将每个其余元素的最后一个元素打印在单独的行上。

eMf|!}K\=eT&Jf}+dhceTK++dYdPT!}KeJ_.__.z
                                      .z  all input lines
                                     _    reverse order
                                   ._     all prefixes
                                  _       reverse order
  f                                       filter for elements T, which satisfy:
      K\=                                   K = '='
    !}K  eT                                 '=' is not in T[-1]
   |                                        or
             f             PT                 filter for elements Y in T[:-1],
                                              which satisfy:
                 hceTK                          extract variable name of T[-1]
                                                with an additional space at the end
               +d                               and at the beginning
              }       ++dYd                     ^ in space+Y+space
            J                                 assign these list to J
           &                                  J not empty and
                             !KeJ             '=' is not in J[-1]
eM                                        take the last element of each and print

8
太可爱了….__.
orlp 2015年

这段代码在pyth.herokuapp.com/…
isaacg

@isaacg固定。
2015年

4

CJam,49个字节

LqN/W%{_'=#_){(<:V1$\e=_{\Va-\}&}{;S/+1}?},\;W%N*

在线尝试

这里的方法是在处理输入行时,要保留未分配变量的列表:

  • 如果该行是表达式,则表达式中的所有变量都将添加到列表中。实际上,在实现中,所有令牌都添加到列表中,因为它可以节省代码并且列表中包含数字和运算符不会造成任何危害。

  • 如果该行是分配,则测试分配的变量名称是否在列表中。如果是,则接受分配,并将变量名称从列表中删除。否则,将跳过分配。

说明:

L     Start with empty list.
qN/   Get input and split at newlines.
W%    Reverse to process lines back to front.
{     Start of filter block.
  _     Copy line.
  '=#   Find equal sign.
  _     Copy position of equal sign, will use original later to extract
        variable name from assignment.
  )     Increment to produce truthy/falsy value (-1 from find means not found).
  {     Start if-block that processes assignments.
    (<    Slice off everything but variable name.
    :V    Save in variable V for later re-use.
    1$\   Place copy of unassigned variable list and new variable name at
          top of stack.
    e=    Count occurrences. This tells us if variable name was in list.
    _     Copy the condition value because it will also be used as the
          overall filter result.
    {     Start of block that removes variable name from list.
      \V    Bring list to top, and push variable name.
      a-    Remove the variable name from list.
      \     Swap to get variable list to bottom of stack for next iteration,
            and filter result to top.
    }&    End of conditional block to remove variable name.
  }     End of if-block for assignment.
  {     Start of else-block for expression.
    ;     Pop result of find operation.
    S/    Split expression at spaces.
    +     Concatenate the new variables with the existing ones in the list.
    1     Filter result, expressions are always accepted.
  }?    End of if for assignment vs. expression.
},    End of filter.
\;    Get rid of variable list at bottom of stack.
W%    Reverse order of filtered result, since we worked back to front.
N*    Join with newlines.

4

Python 2中,270个 267字节

import sys,re
d={}
s=list(enumerate(sys.stdin))
for n,l in s:
 try:v,_=l.split('=');v=v.strip();d[v]=d.get(v,[])+[[0,n]]
 except:
  for v in re.findall('[a-zA-Z_]\w*',l):d[v][-1][0]+=1
print''.join(l for n,l in s if n not in[n for x in d.values()for c,n in x if c==0])

缩进为:1.空格2.制表符

感谢@Kamehameha,节省了3个字节!


在印刷后的空间print ''.join,并inin [n可以被删除。
Kamehameha 2015年

另外,您可以通过在行后使用a 而不是双精度空格并保存一个字节来使用技巧。tabexcept
Kamehameha 2015年

2

R 144

Q=R=c()
for(L in rev(scan(,"",,,"\n"))){W=strsplit(L," ")[[1]]
if("="%in%W)if(W[1]%in%R)R=R[R!=W[1]]else next else R=c(R,W)
Q=c(L,Q)}write(Q,"")

哪里

  • L 是输入的一行(从最后一个开始)
  • W 是一行中的符号(变量,运算符,数字)
  • R是将要打印的符号的向量。它包括需要分配的变量。
  • Q 是输出中线的向量

您可以替换scan(what="",sep="\n")scan(,"",sep="\n")。您也许还可以将命名sep参数替换为其位置等效参数,但我不记得逗号在哪里。
Alex A.

...节省6.非常好。谢谢亚历克斯!
flodel

2

JavaScript(ES6)164 177

使用模板字符串,所有换行符都有效并计数。

FireFox中测试运行代码段(要求具备ES6兼容性,包括箭头功能)

f=s=>(k=>{s=s.split`
`,s.map((t,n)=>(r=t.match(/\w+/g)).map(v=>k[v]=f,~t.search`=`?k[s[k[v=r[0]]]=r[0]=0,v]=n:0))
for(v in k)s[k[v]]=0})([])||s.filter(r=>r).join`
`

ungolfed=s=>
{
  k={} // list line defining variables, by name, until used
  s=s.split`\n`
  s.forEach((t,n)=>
  {
    r=t.match(/\w+/g); // list variables in the line, operators are lost
    if (t.search`=` >= 0) // if it's an assignment
    {
      v=r[0] // new variable
      s[k[v]]=r[0]=0 // kill previous definition if not used
      k[v]=n
    }
    r.forEach(v=>k[v]='') // for each used variable, forget its definition line
  })
  for(v in k)s[k[v]]=0; // kill all remaining unused definitions
  return s.filter(r=>r).join`\n`
}

// TEST
out=x=>O.innerHTML+=x+'\n';


;[['a = 10\na * 3', 'a = 10\na * 3']
 ,['foo = 8\n2 - 1\na = 18','2 - 1'] 
 ,['a = 10\na = 8\nb = 4\nab = 72\nb / 6\nb + 1','b = 4\nb / 6\nb + 1'] 
 ,['a = 1\na = 2\na + 1','a = 2\na + 1'] 
 ,['FooBar1 = 0\nFuz__ = 8\nFuz__ / 1','Fuz__ = 8\nFuz__ / 1'] 
 ,['a = 1\na + 1\na = 2\na + 1','a = 1\na + 1\na = 2\na + 1']
 ,['a = 1\na + a\na = 2', 'a = 1\na + a']
 ,['a = 1\n1 / 5 * 8 + 4', '1 / 5 * 8 + 4']
 ,['a = 1\na + a\na = 2', 'a = 1\na + a']
 ,['a = 1\na + 1\na = 1\na + 1', 'a = 1\na + 1\na = 1\na + 1']
 ,['a = 7\n5 / a', 'a = 7\n5 / a']
]
.forEach(([i,k])=>(r=f(i),
  out('Test '+(r==k?'OK':'Fail')+'\nInput:  '+i.replace(/\n/g,',')
      +'\nResult: '+r.replace(/\n/g,',')
      +'\nCheck:  '+k.replace(/\n/g,',')+'\n')
));
Note: newlines trasformed to commas to save space in output
<pre id=O></pre>


嘿,那不是164个字节!
Cyphase

@Cyphase行1:20 + 1换行,行2; 92 + 1换行,行3:48 + 1换行,行4:1。21 + 93 + 49 + 1 =>164。该ungolfed部分仅用于说明。该TEST部分是...嗯,只是猜测...
edc65

我知道。我刚才是开玩笑的。抱歉:)。
Cyphase

1

的JavaScript ES6,79个 75 118字节

s=>s.split`
`.filter((l,i,a)=>(q=l.split`=`)[1]?!~(a.slice(i+1)+0).search(q[0]+'=')&&~s.search(q[0]+'[^=]'):1).join`
`

告诉我这是否在某种情况下不起作用。欢迎打高尔夫球。


说明

s=>          // Function with argument "s"
  s.split`   // Splits each line
  `
  .filter(   // Filters through each line,
    (item,index,array)=>
      (q=l.split`=`)[1]? // If there is something after the equal sign
        !~ // XOR (~) will  essentially make -1, 0. NOT (!) will make 0, 1, vice-versa
         (a.slice(i+1)+0) // Gets following lines
         .search`^${z=q[0]}=` // Checks if following lines have the same variable name and then =
        && // AND...
         ~s.search(z+'[^=]') // Check if there is an expression with the variable
        :1) // If there is no equal sign, return 1 (true)
  .join` // Join everything back, seperated by newlines
  `

已在Safari Nightly上测试。Firefox友好版本:

s=>s.split`
`.filter((l,i,a)=>(q=l.split`=`)[1]?!~(a.slice(i+1)+0).search(`^${z=q[0]}=`)&&~s.search(z+'[^=]'):1).join`
`

您可以插入babeljs以获得ES5版本。


@黑洞我已经解决了。
Downgoat,2015年

根据示例,@ edc65分隔符是换行符。输入还与空间等严格的格式
Downgoat

@ edc65您确定吗?尝试将函数包装在括号中并像这样运行它。它对我有用(Safari Nightly)。
Downgoat,2015年

也许我固执己见,但我仍然觉得在每种情况下都能正常工作太简单了。我使它在Firefox中运行时没有错误,并在搜索调用中添加了括号(仍然比我的短)。并尝试“ a = 1 \ na + a \ na = 2”。失败了...
edc65

感谢您在回答中添加我的建议。-1,因为它仍然窃听
edc65

1

Haskell,187个字节

使用d

import Data.List
f=filter
(!)=map
b((v,e,w):t)=e||or((\(_,p,_)->p)!take 1(f(\(x,_,y)->v==x||v`elem`y)t))
d=unlines.(\l->snd!f fst(zip(b!tails(((\(v:o:w)->(v,o/="=",w)).words)!l))l)).lines
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.