Авторские статьи Пишем двуязычную программу

Discussion in 'Статьи' started by <Cyber-punk>, 1 Nov 2011.

  1. <Cyber-punk>

    <Cyber-punk> Smash the Stack

    Joined:
    1 Oct 2009
    Messages:
    658
    Likes Received:
    315
    Reputations:
    430
    Недавно передо мной встала нелёгкая задачка, которую мне подкинул один знакомый. Суть состоит в том, чтобы, написав один исходник, можно было его скомпилировать в gcc и исполнить, также и исполнить через интерпретатор perl. Казалось бы, не так уж и сложно, но не всем программистам придёт в голову, как правильно написать данный исходник. Приступим к рассмотрению изначальных программ на C и Perl.

    Голый Си:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    int main(int argc, char *argv[])
    {
      int sum=0;
      int i;
      for (i=1; i<argc; i++)
        sum+=atoi(argv[i]);
      printf("%d\n", sum);
    return 0;
    }
    
    Проверяем:
    Code:
    cyber@punk:/opt# gcc test.c -o test1
    cyber@punk:/opt# ./test1 -2 15 -13
    0
    cyber@punk:/opt# ./test1 2 4 6
    12
    
    Теперь аналог на Perl:
    Code:
    #!/usr/bin/perl
    
    $sum=0;
    foreach (@ARGV) {
     $sum+=$_;
    }
    print "$sum\n";
    
    Снова проверяем:
    Code:
    cyber@punk:/opt# perl test.pl 3 15 10 20
    48 
    
    Теперь приступим решению поставленной задачи.
    Приведу сразу готовый исходник для рассмотрения:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    #define $ /* */
    
    #define ARGV argv
    
    #define if($x) int main(int argc, char *argv[])
    
    #define $start 1  
    
    #if PERL
     sub atoi { $_[0] }
     $ argc=@ARGV;
     $ start=0;
     $ x=1;
    #endif
    
    if($x)
    {
     int $ sum;
     int $ i;
     
     $ sum=0;
    
     for ( $ i = $start; $ i < $ argc ; $ i++) {
       $ sum += atoi ($ ARGV [$ i]);}
    
     printf("%d\n", $ sum);
    
    exit(0);
    }
    
    Тестируем результат:

    Code:
    cyber@punk:/opt# perl test4.c 3 15 10 20
    48
    cyber@punk:/opt# gcc test4.c -o test4
    cyber@punk:/opt# ./test4 3 15 10 20
    48
    
    Давайте рассмотрим хитрости обоих языков, использованные при написании.
    • Perl интерпретирует знак #, как начало комментария до конца строки, это дает возможность использовать директивы препроцессора Си, которые Perl будет игнорировать.
    • Синтаксис языка Perl допускает пробел между знаком $ и именем переменной. Поэтому определение #define $ /* */ позволит в Си интерпретировать переменную вида $ var, как var, а в perl - как $var.
    • В Си параметры командной строки передаются как char *argv[], а в perl - ARGV. Проблему решает директива: # define ARGV argv.
    • В Си нулевой аргумент - это имя программы, а в Perl ARGV - переданный параметр. Обходится это введением переменной start, которая в Си устанавливается в единицу, а в Perl - в ноль. Кусок кода Perl экранируется в Си директивой #if PERL.
    • Синтаксис операторов for и printf в Perl и Си одинаков, поэтому никаких дополнительных мер тут не требуется.


    На этом, в принципе, и все. Возможно у вас есть другие методы написания подобных "двуязычных" программ. С нетерпение жду ваших решений!
     
    _________________________
    7 people like this.
  2. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    936
    Likes Received:
    162
    Reputations:
    27
    Интересная статья. Правда такая двуязычная программа может потребоваться только в каком то экзотическом случае.
    При написании кода нужно учитывать то, что пишем под два языка, поэтому нужно быть особенно внимательным, учитывать всевозможные нюансы.
     
  3. fox_malder

    fox_malder Active Member

    Joined:
    28 Nov 2008
    Messages:
    162
    Likes Received:
    131
    Reputations:
    73
    Кибер панк как всегда на высоте))) с удовольствием прочитал статью) конечно такое часто не станешь применять только тогдав когда вообще выхода нету и путь лежит через извращения