느긋한 계산과 엄격한 계산

아직 제출이 없습니다시간 제한1초메모리 제한128 MB

문제

실무에서 쓰이는 대부분의 프로그래밍 언어는 엄격한 계산(strict evaluation) 을 사용한다. 함수를 호출하면 인자로 넘긴 식을 먼저 계산하고, 그 결과 값을 함수에 전달한다. 그러나 이것이 유일한 방법은 아니다. 어떤 언어는 특정 연산자에 대해 느긋한 계산(lazy evaluation) 을 수행한다(예를 들어 C++의 &&|| 는 결과를 결정하는 데 필요한 만큼의 인자만 계산한다).

작은 식 언어를 정의하고, 느긋한 계산과 엄격한 계산에서 각 산술 연산이 몇 번 실행되는지를 세어 보자.

식. 식은 다음 중 하나이다.

  • 상수: 부호 있는 32비트 정수. 예: 3, 0, -2, 123.
  • 이름: 내장 함수 또는 사용자 정의 함수의 이름. 이름은 소문자 영문 알파벳 최대 32글자로 이루어진 단어이다. 예: f, add.
  • 함수 호출: (function arg1 ... argN) 형태. 여기서 function 은 $N$개의 인자를 받는 함수로 계산되는 식이고, arg1 ... argN 은 인자로 넘길 식이다. 예: (f 3 5), (add 2 (add 1 2)).

계산 규칙.

  • 상수는 자기 자신으로 계산된다.
  • 이름은 그것이 가리키는 함수로 계산된다.
  • 함수 호출은 다음과 같이 계산된다.
    • 느긋한 계산에서는 함수 식을 먼저 계산한 뒤, 각 형식 매개변수를 대응하는 인자 에 묶어 본문을 계산한다. 인자 식은 그 값이 실제로 필요할 때에만, 그리고 많아야 한 번만 계산된다. 한 번 계산되면 그 값이 해당 매개변수의 모든 출현을 대체한다(메모이제이션).
    • 엄격한 계산에서는 모든 식을 먼저 계산한다(함수 식은 함수로, 인자는 값으로). 그런 다음 각 형식 매개변수를 대응하는 인자 값으로 치환하여 본문을 계산한다.

내장 함수 (모두 두 개의 인자를 받는다):

함수결과
add x y$x + y$
sub x y$x - y$
mult x y$x \times y$
div x y정수 나눗셈 (C/C++/Java의 /)
rem x y나머지 (C/C++/Java의 %)
true x y$x$ (항상 첫 번째 인자)
false x y$y$ (항상 두 번째 인자)
eq x y$x$ 와 $y$ 가 같은 상수이면 true, 아니면 false
gt x y$x > y$ 이면 true, 아니면 false

eqgt 는 함수 true/false 를 돌려주므로, 불리언 값이 두 갈래 선택자 역할을 겸한다.

사용자 정의 함수name arg1 ... argN = body 문법으로 정의한다. arg1 ... argN 은 서로 다른 단어(소문자 최대 32글자)로 형식 매개변수이며, body 는 상수나 이름이 올 수 있는 자리에 매개변수가 나타날 수 있는 식이다. 인자가 없는(0개) 함수도 허용된다. 형식 매개변수는 함수 이름을 가릴 수 있으나, 함수 이름은 모두 서로 다르다.

내장 함수의 인자 계산. 엄격한 계산에서는 모든 내장 함수가 자신의 인자를 모두 계산한다. 느긋한 계산에서는 add, sub, mult, div, rem, eq, gt 는 두 인자를 모두 계산하지만, truefalse 는 자신이 돌려주는 한쪽 인자만 계산한다.

오버플로와 나눗셈. 모든 산술은 부호 있는 32비트 정수에서 이루어지며, C/C++/Java의 +, -, *, /, % 연산자와 똑같이 넘침(wrap-around)이 일어난다. divrem 은 0 쪽으로 절삭(truncate toward zero)한다. 0으로 나누는 경우는 없다.

정지하지 않는 경우. 각 테스트 식에 대해, 느긋한 계산과 엄격한 계산 중 어느 한쪽이라도 $2345$번의 함수 계산을 넘겨도 끝나지 않으면 그 식은 무한 루프로 간주한다. 그 식은 통째로 건너뛰고, 어느 쪽 계산에서도 그 식의 연산 횟수를 전혀 더하지 않는다.

입력

입력은 두 부분으로 이루어진다.

첫 번째 부분에는 $1000$개 미만의 함수 정의가 한 줄에 하나씩 주어지고, 그 뒤에 빈 줄 하나가 온다. 전방 참조(뒤에 정의되는 함수를 먼저 참조하는 것)와 재귀가 허용된다.

두 번째 부분에는 $1000$개 미만의 테스트 식이 한 줄에 하나씩 주어지고, 그 뒤에 빈 줄 하나가 온다. 함수 이름과 인자는 하나의 공백으로 구분되며, 괄호 주위에는 여분의 공백이 없다. 각 식은 느긋한 계산과 엄격한 계산 두 방식 모두로 계산된다.

모든 정의와 식은 문법적으로 올바르며, 산술 내장 함수는 항상 정수에만 적용되고, 0으로 나누는 경우는 없다. 각 줄은 최대 $255$글자이다.

출력

건너뛰지 않은 모든 테스트 식에서 각 산술 연산이 몇 번 실행되었는지를 정확히 여섯 줄로 출력한다.

첫 줄은 머리글 operator lazy strict 이다. 다음 다섯 줄은 각각 op lazy strict 형태이며, opadd, sub, mult, div, rem 중 하나이다(이 순서대로). lazy 는 느긋한 계산에서 op 가 실행된 총 횟수, strict 는 엄격한 계산에서의 총 횟수이다. 각 줄의 토큰은 공백 하나로 구분한다.

operator lazy strict
add <lazy> <strict>
sub <lazy> <strict>
mult <lazy> <strict>
div <lazy> <strict>
rem <lazy> <strict>

이 다섯 개의 산술 연산만 센다. true, false, eq, gt 는 절대로 세지 않는다.