Recursive-Descent parsing으로 계산기 짠건데.. 질문이 있습니다.

korea0130의 이미지

재귀를 이용하여 간단한 계산기 짜는 프로그램인데요.. (계산기를 짠다기보다 인터프리터를 짠다는게 맞는거 같긴하지만..)

예를들어 12+3을 입력하면 15가 나오는 프로그램입니다.

다 생략하고 궁금한 부분만 올리겠습니다.

함수를 돌고 돌다 마지막 값을 구하는 함수(number함수)에서

n = n*10 + c-'0';

이런게 있는데... c-'0' 이걸 하는 이유가 뭔가요?

n*10은 이해가 되는데.. 뒤에 c에 '0'을 빼주는 이유가 뭔가요?ㅠㅠ

#include
#include
#include

int c;
int expression(void);

void error(char *msg) {
puts(msg);
exit(1);
}

void next(void) {
c = getchar();
if (c==EOF) error("char expected");
}

int number(void) {
int n;

if (!isdigit(c)) error("digit expected");
n = 0;
do {
n = n*10 + c-'0';
next();
} while (isdigit(c));
return n;
}

int factor(void) {
int n;

if (c=='(') {
next();
n = expression();
if (c!=')') error(") expected");
next();
} else
n = number();
return n;
}

int term(void) {
int op, n, m;

n = factor();
while ((op=c)=='*' || op=='/') {
next();
m = factor();
n = op=='*' ? n*m : n/m;
}
return n;
}

int expression(void) {
int sign, op, n, m;

if ((sign = c=='-') || c=='+') next();
n = term();
if (sign) n = -n;
while ((op=c)=='+' || op=='-') {
next();
m = term();
n = op=='+' ? n+m : n-m;
}
return n;
}

int main(void) {
next();
printf("%d\n", expression());
return 0;
}

익명 사용자의 이미지

1. getchar로 반환한 값은 '문자'입니다. 숫자가 아니에요.
십진 숫자 문자 하나, 예컨대 '5'를 입력받았다고 할 때, c에 저장될 값은 '5'라는 문자에 대응되는 코드 값이지, 숫자 5가 아닙니다.

2. 그러므로, 문자 '5'를 숫자 5로 바꿀 수 있는 방법이 필요합니다.
ASCII에서는 '5'에 대응되는 코드 값이 16진수 35입니다. '6'은 16진수 36, 등등. '0'은 16진수 30이지요.
다시 말해, 문자 '0', '1', ... '9'가 ASCII 코드표 상에 연속적으로 16진수 30~39에 위치하고 있는 겁니다.
그래서 c - '0'을 하면 딱 c가 나타내는 십진 숫자 문자에 대응하는 숫자를 얻을 수 있는 것입니다.

3. 근데 문자셋이 ASCII가 아니라면요?
요즘에야 이런 걱정을 할 필요가 있는 경우를 상상하기가 거의 어렵습니다만, 초중고 컴퓨터 교과서에서나 가끔 들어보셨을 법한 EBCDIC이라는 문자셋 혹시 기억하시는지?
예컨대 이 문자셋을 사용중일 때는 위 테크닉을 사용할 수 없지 않습니다.

농담이고요. EBCDIC에서도 '0'~'9'는 연속적으로 16진수 F0~F9에 위치하고 있기 때문에 위 테크닉을 그대로 쓸 수 있습니다. 'a'~'z'가 연속하여 위치하지 않은 독특한 문자셋인데, 다행이군요.
흠, 하지만 정말로 예외가 없을까요?

4. 드높은 천상의 C언어 표준은 '0'~'9'를 불연속적으로, 혹은 엉뚱한 순서로 문자셋에 배치하는 것을 엄격히 금합니다. 그게 소스 코드를 나타내는 데 쓰는 문자셋이든, 컴파일된 결과물이 실행될 때 쓰이는 문자셋이든 말이죠.
그래서, "C언어"를 사용할 수 있는 모든 환경에서 (c - '0')은 항상 c가 나타내는 십진 숫자 문자에 대응되는 숫자를 얻게 됩니다.

이 점을 볼 때, 웬만하면 (c - 0x30)보다는 (c - '0')을 쓰는 게 더 좋다는 근거가 되기도 하지요. 프로그래머의 의도가 좀 더 분명해 보일 뿐만 아니라, 아주 미약하게나마 이식성도 더 좋아집니다.

korea0130의 이미지

와.. 감사합니다.

아직 초보 프로그래머라.. 많이 배워갑니다!

감사해요~!

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.