70. VFR의 상수 및 연산자가 내장된 기본 조건문

ideqval/ideqvalist/ideqid/questionref/pushthis

지난 수업에서 우리는 어디에서나 TRUE 상수를 사용했다. 다음 VFR에서 사용할 수 있는 IFR 코드와 관련된 다른 상수이다.

"TRUE"		EFI_IFR_TRUE 
"FALSE"		EFI_IFR_FALSE
"ONE"		EFI_IFR_ONE 		 (=1)
"ONES"		EFI_IFR_ONES		 (=0xFFFFFFFFFFFFFFFF)
"ZERO"		EFI_IFR_ZERO             (=0)
"UNDEFINED"	EFI_IFR_UNDEFINED	 (=Undefined)
"VERSION"	EFI_IFR_VERSION 	 (=UEFI specification to which the Forms Processor conforms)

당연히 숫자 상수도 있다. 이는 아래 type중 하나이다.

EFI_IFR_UINT8
EFI_IFR_UINT16
EFI_IFR_UINT32
EFI_IFR_UINT64

숫자에 대해서도 여러가지 작업이 지원된다.

"+"		EFI_IFR_ADD
"-"		EFI_IFR_SUBTRACT
"*"		EFI_IFR_MULTIPLY
"/"		EFI_IFR_DIVIDE
"%"		EFI_IFR_MODULO
"|"		EFI_IFR_BITWISE_OR
"&"		EFI_IFR_BITWISE_AND
"=="		EFI_IFR_EQUAL
"!="		EFI_IFR_NOT_EQUAL
"<"		EFI_IFR_LESS_THAN
"<="		EFI_IFR_LESS_EQUAL
">"		EFI_IFR_GREATER_THAN
">="		EFI_IFR_IFR_GREATER_EQUAL
"<<"		EFI_IFR_SHIFT_LEFT
">>"		EFI_IFR_SHIFT_RIGHT
"~"		EFI_IFR_BITWISENOT

다음은 논리 연산자이다.

"OR"		EFI_IFR_OR
"AND"		EFI_IFR_AND
"NOT"           EFI_IFR_NOT

삼항 연산자(if-then-else의 약식, 즉 <...> ? <...> : <...>)도 VFR에서 다음 형식으로 지원된다.

cond( <...> ? <...> : <...> )		EFI_IFR_CONDITIONAL

casts

다음과 같은 간단한 작업이 가능하다.

suppressif 0;
  ...
endif;

숫자를 bool로 취급할 때는 명시적으로 bool로 변환해야 한다. 그렇지 않으면 찾기 어려운 오류의 원인이 될 수 있다. 예시는 다음과 같다.

suppressif (1 OR 0);                    // element is present (incorrect)
  ...
endif;

suppressif ((BOOLEAN)1 OR (BOOLEAN)0);  // element is not present (correct)
  ...
endif;

다음은 코드에서 사용할 수 있는 전체 cast 목록이다.

"(BOOLEAN)"	EFI_IFR_TO_BOOLEAN
"(UINT64)"	EFI_IFR_TO_UINT
"(UINT32)"
"(UINT16)"
"(UINT8)"

이 cast 외에도 다음을 사용할 수 있다.

boolval(<...>)		EFI_IFR_TO_BOOLEAN
stringval(<...>)	EFI_IFR_TO_STRING
unintval(<...>)		EFI_IFR_TO_UINT

ideqval

질의 값을 UINT16과 비교하려면 ideqval 구문을 사용 가능하다.("id equal value"의 약어이다.)

EFI_IFR_EQ_ID_VAL

Summary:
Push TRUE if a question’s value is equal to a 16-bit unsigned integer, otherwise FALSE.

Prototype:

#define EFI_IFR_EQ_ID_VAL_OP 0x12

typedef struct _EFI_IFR_EQ_ID_VAL {
 EFI_IFR_OP_HEADER Header;
 EFI_QUESTION_ID QuestionId;
 UINT16 Value;
} EFI_IFR_EQ_ID_VAL;

Members:
Header 		Standard opcode header, where OpCode is EFI_IFR_EQ_ID_VAL_OP.
QuestionId 	Specifies the identifier of the question whose value will be compared.
Value 		Unsigned integer value to compare against.

Description:
Evaluate the value of the specified question (QuestionId). If the specified question cannot be evaluated as an unsigned integer, then push Undefined. If they are equal, push TRUE. Otherwise push FALSE.

예를 들어 다음과 같은 표현식이 허용된다.

suppressif ideqval FormData.CheckboxValue == 1;
  ...
endif;

suppressif ideqval FormData.NumericValue == 7;
  ...
endif

suppressif ideqval FormData.OneOfValue == 0x33;
  ...
endif;

이는 form browser가 다른 요소의 값을 기반으로 요소를 동적으로 숨기거나 표시함을 의미한다.

언어 구문에 어긋나고 정의되지 않은 동작을 유발할 수 있으므로 == 대신 아무 것도 입력하면 안된다. 값이 다른지 테스트하지 않으려면 NOT 키워드를 활용할 수 있다.

suppressif NOT ideqval FormData.OneOfValue == 0x33;
  ...
endif;

ideqid

ideqid("id equal id"의 약어)은 다음 형식에서 두 질문의 값을 비교할 수 있다.

EFI_IFR_EQ_ID_ID

Summary:
Push TRUE if the two questions have the same value or FALSE if they are not equal.

Prototype:

#define EFI_IFR_EQ_ID_ID_OP 0x13

typedef struct _EFI_IFR_EQ_ID_ID {
 EFI_IFR_OP_HEADER Header;
 EFI_QUESTION_ID QuestionId1;
 EFI_QUESTION_ID QuestionId2;
} EFI_IFR_EQ_ID_ID;

Members:
Header				Standard opcode header, where OpCode is EFI_IFR_EQ_ID_ID_OP.
QuestionId1, QuestionId2	Specifies the identifier of the questions whose values will be compared.

Description:
Evaluate the values of the specified questions (QuestionId1, QuestionId2). If the two values cannot be evaluated or cannot be converted to comparable types, then push Undefined. If they are equal, push TRUE. Otherwise push FALSE.

두개의 값이 동일하면 TRUE 동일하지 않으면 FALSE가 반환되며 아래와 같은 양식으로 사용이 가능하다.

suppressif ideqid FormData.OneOfValue == FormData.NumericValue
  ...
endif;

questionref

위의 명령문(ideqval/ideqvallist/ideqid)은 동등성에 대한 테스트만 허용하며 더 복잡한 계산을 원하면 questionref를 사용 가능하다.

EFI_IFR_QUESTION_REF1

Summary:
Push a question’s value on the expression stack.

Prototype:

#define EFI_IFR_QUESTION_REF1_OP 0x40

typedef struct _EFI_IFR_QUESTION_REF1 {
 EFI_IFR_OP_HEADER Header;
 EFI_QUESTION_ID QuestionId;
} EFI_IFR_QUESTION_REF1;

Members:
Header 		The byte sequence that defines the type of opcode as well as the length of the opcode being defined.
		Header.OpCode = EFI_IFR_QUESTION_REF1_OP.
QuestionId 	The question’s identifier, which must be unique within the form set.

Description:
Push the value of the question specified by QuestionId on to the expression stack. If the question’s value cannot be determined or the question does not exist, then push Undefined.

여기서 한 가지 중요한 변경 사항은 질문 참조가 varid(가변)(예:FormData.NumericValue)이 아니라 질문에서 선언해야 하는 name(이름) 필드의 값을 사용한다는 것이다.

numeric
  name = NumericQuestion,
  ...
endnumeric;

suppressif (BOOLEAN)(questionref(NumericQuestion) % 2);
  ...
endif

해당 코드는 숫자 값이 짝수인 경우에만 요소를 표시한다.

name(이름)을 정의하는 코드는 questionref에서 해당 참조 앞에 와야한다. 반대 상황은 빌드 실패로 이어진다.

pushthis

질문 내에서 pushthis 키워드를 사용하여 질문 값을 얻을 수 있으며 이는 EFI_IFR_THIS로 변환된다.

EFI_IFR_THIS

Summary:
Push current question’s value.

Prototype:

#define EFI_IFR_THIS_OP 0x58

typedef struct _EFI_IFR_THIS {
 EFI_IFR_OP_HEADER Header;
} EFI_IFR_THIS;

Members:
Header 		The sequence that defines the type of opcode as well as the length of the opcode being defined.
		For this tag, Header.OpCode = EFI_IFR_THIS_OP.

Description:
Push the current question’s value.

예를 들면 아래와 같이 사용된다.

numeric
  name = NumericQuestion,
  varid = FormData.NumericValue,
  prompt = STRING_TOKEN(NUMERIC_PROMPT),
  help = STRING_TOKEN(NUMERIC_HELP),
  minimum = 5,
  maximum = 20,
  warningif
    prompt = STRING_TOKEN(WARNING_IF_PROMPT),
    pushthis == 10
  endif;
endnumeric;

이 경우 ideqval 또는 questionref를 사용하여 유사한 결과를 얻을 수 있다. 다음 문은 동일하다.

ideqval FormData.NumericValue == 10

questionref(NumericQuestion) == 10

pushthis == 10

다른 예시는 다음과 같다.

string
  varid = FormData.StringValue,
  prompt = STRING_TOKEN(STRING_PROMPT),
  help = STRING_TOKEN(STRING_HELP),
  minsize = 5,
  maxsize = 10,
  warningif
    prompt = STRING_TOKEN(WARNING_IF_PROMPT),
    pushthis == stringref(STRING_TOKEN(TEST_STRING))
  endif;
endstring;

여기서 사용자가 문자열 양식 요소에 "EDKII"를 입력하면 경고 창이 나타난다.

Last updated