Programming Languages [PL]

[PL] 06. Expressions and Assignment Statements

Coulson 2024. 1. 10. 09:44

Expression

프로그래밍 언어에서 computation을 특정하는 기본 수단

 

V : (State, Expr) -> Value

V는 상태 S에서의 E의 값

S = {x=1, y=2} , V(S, x+y) = 3

  • 산술 계산 Arithmetic Expression : V(s, E1+E2) = V(s, E1) + V(s, E2)
  • 비교 연산 Relational Expression = 논리 연산 Boolean : V(s, E1==E2) = T if V(s, E1) == V(s, E2)
  • Logic Expression

Logic Expression


Arithmetic Expression

초기 프로그래밍 언어 개발의 동기

 

구성

  • operator(연산자)
  • operand(피연산자)
  • 괄호
  • function call(함수 호출)

Operator : 단항 연산자, 이항 연산자, 삼항 연산자 (각각 1, 2, 3개의 피연산자를 가짐)


Design Issues

  1. 연산자 우선순위
  2. 연산자 결합성
  3. 피연산자의 평가 순서
  4. 연산자의 피연산자로 function call이 쓰였을 때, 그 function으로 인한 side effect는 어떻게 처리할 것인지
  5. 연산자 overloading을 허용할 것인지 (C/Java는 허용 X , C++/Python은 허용)
  6. 하나의 수식에 여러 Type을 가진 변수들이 섞여 있으면 어떻게 처리할 것인지 (Type mixing) 

일반적인 연산자 우선순위 (Operator Precedence Rules)

서로 다른 우선순위 수준을 가진 "인접한" 연산자의 평가 순서를 정의

  1. 괄호
  2. 단항 연산자
  3. 지수(**)
  4. * /
  5. + -
  6. (그 뒤: 비교 -> 논리(&&, ||) -> 조건(?, :) -> 대입)

연산자 결합성 (Operator Associativity Rule)

동일한 우선순위를 갖는 연산자가 두 개 이상 인접한 경우, 무엇을 먼저 수행하느냐에 대한 규칙

  1. Left to Right (left associative) (대부분의 이항 연산자)
  2. Right to Left (right associative) (대부분의 단항 연산자와 대입 연산자, 그리고 지수 연산자(**))

APL의 초기 버전 : 모든 operator의 우선순위 같고 결합은 ‘Right to Left’로 수행함


Operand Evaluation Order (피연산자 평가 순서)

  1. Variables 변수 : 메모리에서 값을 가져온다.
  2. Constants 상수 : 메모리에서 가져오거나, 코드 자체에 들어가 있을 수 있음. 코드가 내재하고 있다.
  3. 괄호 : 먼저 계산한다.
  4. function call이 operand로 쓰였을 때 그로 인한 영향을 연산자 계산 이전에 반영? 혹은 이후에 반영?
    function call이 Expression의 변수의 값을 안 바꾸면 상관 X, 바뀌는 경우 => Global 변수, 2-way parameter

Function Side Effects의 2가지 해결법

  1. function call에 의해서 피연산자의 값이 안 바뀌도록 -> Global 변수, 2-way parameter 을 못쓰게 한다. function에서 parameter change와 non-local reference가 없게 => 프로그램의 flexibility가 떨어진다. 
  2. function call에 의해서 바뀌는 값의 순서를 명확하게 지정 => compiler optimization(최적화)이 제한된다.

Referential Transparency를 보장한다.

-> 같은 함수에 같은 파라미터가 들어가면 같은 리턴값이 나오게 한다.

 

같지 않게 만드는 경우

  1. Global 변수
  2. 2-way parameter
  3. Local 변수이지만 Static일 때

Referential Transparency의 장점 : Readability 높아짐, 프로그램의 Semantic(의미)를 이해하기 쉽다. (참조 투명성) 

완벽한 Referential Transparency를 보장하는 언어는 functional language (변수를 안 쓰는 언어, 모든 값은 상수)


Overloaded Operators

잘 사용하면 Readability를 높이지만 오히려 헷갈리게 만들 수도 있다. 

Python, C++은 User defined operator overload를 지원한다. C, Java는 지원 X (Java의 String ‘+’는 예외 사항)


Type Conversions

  • 명시적인 타입 변환 Type Casting (개발자가 명시적으로 표기하는 것이므로 거의 모든 프로그래밍 언어는 지원)
  • 암묵적인 타입 변환 Coercion (장점 : Flexibility 상승, 단점 : Reliability 하락) (Imperative 프로그래밍 언어에서는 지원) (Functional 프로그래밍 언어는 허용 X) (-> 작은 것에서 큰 것으로 갈 때(widening conversion)는 해준다. 반대는 X)
  • Narrowing conversion = float to int (큰 것에서 작은 것으로 좁힘)
  • Widening conversion = int to float (대부분 문제가 안 됨) (작은 것에서 큰 것으로 넓힘)

Mixed Mode (Coercion이 되어야 가능 = Functional 프로그래밍 언어는 명시적으로 변환해줘야 사용 가능)

Errors in Expressions : 수학적 문제 (zero-division) / 컴퓨터의 한계 (overflow) -> Error는 run-time system에 의해 자주 무시됨


비교 연산 Relational Expression / 논리 연산 Boolean Expression

Relational Expression

  • Relational Operator와 다양한 타입의 피연산자를 사용
  • Boolean 형태로 평가
  • JavaScript와 PHP에는 ‘===’와 ‘!==’라는 두 가지 추가적인 관계 연산자가 존재
  • 이 연산자들은 ‘==’와 ‘!=’와 유사하지만, 피연산자를 강제 coercion하지 않는다.
  • Ruby는 ‘==’를 coercion하는 등호 관계 연산자로 사용, coercion이 필요하지 않은 경우에는 ‘eql?’을 사용

Boolean Expression

피연산자가 Boolean이고 결과도 Boolean이다.

C에서 a<b<c는 a<b의 결과가 0 또는 1로 나오고 그 값이 c와 비교되므로 원하는 대로 계산이 되지 않는다.


Short Circuit Evaluation

(Expr1) && (Expr2) 에서 Expr1이 False이면 Expr2는 평가를 하지 않고 그냥 0을 리턴
4가지 언어 모두 Short Circuit Evaluation을 지원함

(&&, ||) / 비트 연산자 &와 |는 Short Circuit을 사용하지 않음

( a < b ) || ( b++ / 3) => 앞 expression의 참/거짓 여부에 따라 side effects가 발생할 수 있음


Assignment Statements
<target_var> <assign_operator> <expression>
assign_operator는 Fortran, BASIC, C기반 언어는 ‘=’ / Ada는 ‘:=’


Compound Assignment Operator

+= 등. ( a = a + b => a += b)


Unary Assignment Operator (단항 연산자)

++. --

sum = ++count : count 증가 후 대입

sum = count++ : 대입 후 count 증가

count++ : count 증가

-count++ : count 증가 후 부정 (int count = 5; int result = -count++; result는 -6, count는 6)


Assignment statement의 결과는 Expression으로 Operand로 쓰일 수 있다. ex) (ch = getchar()) != EOF
단점 : Expression side effect를 발생시킬 수 있다. 

 

Multiple Assignments
Perl, Ruby, Lua 등, (&first, &second, &third) = (20, 30, 40); / (&first, &second) = (&second, &first);

C/C++은 같은 값을 다른 변수에는 넣을 수 있음.

Python은 다른 값을 다른 변수에도 넣을 수 있음. Java는 안 됨

 

Mixed Mode Assignment 

4가지 언어 다 coercion을 지원하므로 지원함