inca: a hacked-up apl in c based on the J incunabulum

Discussion in 'C Programming' started by luser- -droog, Mar 27, 2014.

  1. compiles without warnings (if you don't ask for warnings) with gcc. currently 313 terse lines.

    Questions? Improvements? Style-bashing?


    based on the J-incunabulum,
    lightly extended to allow propagating specifications "a+2+a=3",
    new functions minus,times,unbox. multi-digit integers.
    identity element for monadic use of minus,times,cat.

    Implements monadic functions

    + identity
    { size
    ~ iota
    < box
    # shape
    | absolute
    ! not
    ' transpose
    @ reverse

    dyadic functions

    + plus
    { from
    ~ find
    < assign (not really a function, but an interpreter action)
    # reshape
    , cat
    - minus
    . times
    * power
    % divide
    | modulus
    & and
    ^ or
    = equals?

    monadic operator

    / reduce f/X => x0 f (x1 f (x2 f ( ... xn-2 f xn-1)))

    dyadic operator

    . matrix product Af.gW => f/Ag'W

    over multidigit numbers and variables
    '_'(underscore), '`'(backtick), and a-z
    `'_'`(underscore) is set to the result of the previous line.

    The interpreter also implements a non-greedy "cat" for
    number vectors separated by spaces. Hence `1 2 3+~3` => `1 3 5`
    where `~` is the zero-based iota.

    If the length of the command string exceeds 98 characters,
    the behavior is undefined.

    If array operands have incompatible sizes, the behavior
    is undefined.
    luser- -droog, Mar 27, 2014
    1. Advertisements

  2. luser- -droog

    Tonton Th Guest

    $ man realloc
    Tonton Th, Mar 27, 2014
    1. Advertisements

  3. luser- -droog

    jacob navia Guest

    gcc -g miniapl.c
    [ many warnings ellided ]
    gdb ./a.out
    warning: this program uses gets(), which is unsafe.
    1 + 1

    Program received signal EXC_BAD_ACCESS, Could not access memory.
    Reason: KERN_PROTECTION_FAILURE at address: 0x00000005
    0x00003524 in cat (a=0x17ff10, w=0x1) at miniapl.c:107
    107 V2(cat){I an=tr(a->r,a->d),wn=tr(w->r,w->d),n=an+wn;
    (gdb) print *a
    $1 = {
    t = 0,
    r = 0,
    d = {0, 0, 0},
    p = {1, 0}
    Current language: auto; currently minimal
    (gdb) quit
    The program is running. Exit anyway? (y or n) y

    Obviously I am too stupid to understand

    V2(cat){I an=tr(a->r,a->d),wn=tr(w->r,w->d),n=an+wn;

    1) You use "P" for printf
    2) You use "R" instead of return
    3) C for "char"
    4) "I" for int
    5) No identifier name is longer than two letters
    6) The result of a function is never declared. Implicit int for all
    7) The type of variables is never declared. Implicit int for all variables.

    So, you publish code that only you can read. GREAT!
    jacob navia, Mar 27, 2014
  4. Perhaps a select few others across this wide globe.

    It's definitely a hornet's nest of a pile of code droppings.
    But it kinda all works, if you type the syntax right.

    In your attempt, the spacing was off.

    should work. A space following a number must be
    followed by another number, and it concatenates
    the two into a list terminated by the first

    1 1 1+3 => 4 4 4

    It took me weeks poring over that original J
    incunabulum. Then learning more apl for context,
    then going back to the incunabulum.

    The "byte"-code (actually, integer-code) format
    distinguishes between types by ranges.
    x < 16ish : it's a function or operator
    x >= '_' && x <= 'z' : it's a variable
    x > 'z' : it's a pointer

    This makes the assumption that pointer values
    in the ascii range are never returned by malloc.
    luser- -droog, Mar 27, 2014
  5. luser- -droog

    BartC Guest

    The C code very cleverly resembles APL too.
    Can't you just increase the s[99] in main() to something less likely to be
    exceeded? Such as s[999]. It will still be 313 lines (or 314 as it appears
    to be now).
    BartC, Mar 27, 2014
  6. That part comes from the original source,
    but I've tried to stay true to the original style.
    But there are numerous //commented printfs where
    I've needed to probe what it was doing.
    Certainly that can be done, but it still needs the scary
    warning, I think.
    luser- -droog, Mar 27, 2014
  7. The part I'm really proud of is getting it to do a
    matrix product:
    86400 3600 60 1+..0 2 1 18
    => 7278 .

    The first dot is "dot-product", the second dot is "product".

    I thought about making "power" an operator instead of a function, but it got too weird to think about.

    or never got weird enough, maybe.

    In order to do "base" and "encode" like the APL book describes, I'll need to generate a triangular matrix. And probably a whole prototype matrix family.

    So I'm thinking that'll be a dyadic operator, similar to the circle functions, and maybe I can do rotation/transposition the same way.

    And at some point, I'll want to extend it to handle floating-point numbers and character strings.

    With strings, it can invoke execute as a function, and then variables can hold code.

    Unfortunately, I can't use "dot" as a floating-point notation if it's overloaded already as a function and an operator. :(
    luser- -droog, Mar 27, 2014
  8. luser- -droog

    David Brown Guest

    I guess the original author wanted to write something akin to APL, but
    which could be accepted by a C compiler.
    David Brown, Mar 27, 2014
  9. luser- -droog

    David Brown Guest

    An APL program that exceeds 98 characters is scary - one that exceeds
    998 characters would be terrifying. I don't think a warning is needed!
    David Brown, Mar 27, 2014
  10. luser- -droog

    jacob navia Guest

    Le 27/03/2014 12:23, David Brown a écrit :
    I have programmed in APL for years. I worked in STSC, the main APL
    provider in the 80s, and always my variable names were clear mnemonic
    names. APL is succint, yes, but if you use it correctly you can write
    quite readable software.

    Besides, there is no point in using gets() for a fixed length line.
    lcc-win provides "getline()" and many other compilrs do that too.
    jacob navia, Mar 27, 2014
  11. luser- -droog

    David Brown Guest

    APL is only readable if you have learned to understand the symbols, and
    if you have learned to understand the way of thinking (right-to-left
    parsing without operator precedence, so that 4 * 2 + 3 is 20 in APL).
    So you need to reach a higher level of understanding in APL than many
    other languages before anything is comprehensible. Personally, I never
    got anywhere near that stage when I played a little with APL some 25
    years ago.

    But of course you can write more or less readable code in APL, just as
    you can in C and any other language. It is just that with APL, you can
    take compact and virtually incomprehensible code to new heights that
    would make any IOCC winner cry. You can also write code that /looks/
    like it is a compact and incomprehensible collection of symbols, while
    it is actually perfectly readable to APL experts - you can't do that with C.
    David Brown, Mar 27, 2014
  12. [...]

    typedef char C;
    typedef intptr_t I;
    typedef struct a{I t,r,d[3],p[2];} *A;

    #define P printf
    #define R return

    And that's where I stopped reading.

    I'm curious, though. Why would you write code like that? Is it
    deliberately obfuscated?

    Oh, and inca.c will not compile, since the name intptr_t is not visible.
    (This isn't just an error in the current versions; all 27 versions in
    your repository have the same problem.) If it compiles without error
    for you, there may be something wrong with your C implementation.

    Once you fix that, try compiling on a 64-bit system.
    Keith Thompson, Mar 27, 2014
  13. luser- -droog

    Javier Lopez Guest

    Javier Lopez, Mar 27, 2014
  14. Not really. IOCCC requires more creative obfuscation than hacks like
    "#define R return" that can be resolved just by running the code through
    the preprocessor (which the judges will do).
    Keith Thompson, Mar 27, 2014
  15. As you've commented elsewhere in this thread, it is
    /obscure/ but not very /obfuscated/, per se.

    The goal I think, is compactness. I've lost some
    of that while adding extensions, but I'm still trying
    to keep it "tight", while removing limitations and
    errant behavior.
    Cygwin gcc (GCC) 4.5.3 let me get away with it.
    {shudder}. Touché.
    luser- -droog, Mar 27, 2014
  16. luser- -droog

    BartC Guest

    Why is it necessary to keep it tight?

    (I had a look earlier with a view to expanding it to 'normal' C. But after
    about thirty seconds I gave up! It would be easier to rewrite from scratch.)
    BartC, Mar 27, 2014
  17. luser- -droog

    Javier Lopez Guest

    El 27/03/2014 19:04, Keith Thompson escribió:
    If this wasn't intented for a obfuscation contest, then it is
    deliberately obfuscated and I don't understand the point.
    Javier Lopez, Mar 27, 2014
  18. luser- -droog

    James Kuyper Guest

    That's a pretty nearly worthless goal to be pursuing, and you're
    pursuing at great expense to readability, a far more important goal.
    James Kuyper, Mar 27, 2014
  19. My comment was that its obfuscation would not be suitable for the IOCCC

    That kind of compactness is not a virtue. Abbreviating "return" and
    "printf" (which all C programmers understand) as "R" and "P" serves no
    useful purpose that I can think of. I for one will not waste my time
    trying to read code written in that horrid style.

    (Apparently there are other problems as well, such as depending on
    implicit int and assuming that int and pointers are the same size.)

    If you find it fun to write such code for yourself, you are of course
    free to do so. If you want anyone else to read it, as implied by
    posting it here, going out of your way to make it more difficult
    to read is counterproductive.
    Keith Thompson, Mar 27, 2014
  20. (snip, someone wrote)
    There are still a few cases left where compact is fast, and fast
    is important. For real-time systems, it is either fast enough or
    doesn't work at all.

    The inner loop of an interpreter should also be fast, sometimes
    at the expense of readability. (Though there is no excuse
    for not having enough comments to explain the unreadable part.)

    -- glen
    glen herrmannsfeldt, Mar 27, 2014
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.