Skip to content

Implement dynamic analysis #13

Description

@dspinellis
  • Each thread maintains its own pool of plain variables and associative arrays
  • A reduction operator can be one of the following
    • Ordered assignment (see below)
    • Accumulation, i.e. the operations x++, ++x, x--, --x, x += value, x -= value
    • One of a = min(a, expr), a = max(a, expr), a = and(a, expr), a = or(a, expr), a = xor(a, expr),
  • Variable refers to a plain variable, e.g. a or an associative array cell, e.g. a["apple"]
  • Each variable is associated with
    • a file id (file ordinal number) and file offset, initially undefined
    • an indicator of whether it is used for accumulation or assignment.
  • When an initialized variable is assigned its type indicator is set to the reduction operator used
  • Assigning to a initialized variable with a reduction operator different from the existing one results in a fatal error
  • Reading a variable's value, for an operation other than the use in a reduction operator (accumulation, min, max), results in a fatal error if the variable's associated file id/offset is different from the current file id/offset
  • Before executing the END block the following reduction takes place:
    • Each variable/cell set typed for accumulation is summed across threads into a single value
      with the same name
    • Each variable/cell set typed for min, max, and, or, xor has that function applied
      to the values across threads resulting in a single value with the same name
    • The thread values of assignment reduction variable/array cell are ordered
      by ordinal file id and offset,
      and a single variable is created with the value of the last variable in the ordered set.
    • If some variables in a set are typed differently from others, then a fatal error occurs.
  • Fatal errors indicate the reason, e.g. Line 4, record 54: assignment to an accumulator variable

Error examples and test cases

All examples should also work for an array cell, e.g. a[4].

Variable used in different blocks

NR == 1 { a = 1 }
NR == 2 { a = 2 }

Variable used for both assignment and accumulation

NR == 1 { a = 1 }
NR == 2 { a += 1 }
NR == 1 { a += 1 }
NR == 2 { a = 1 }

Reading from a different record

NR == 1 { a++ }
NR == 1000 { if (!a) print "Error" }
NR == 1 { a++ }
NR == 1000 && !a { print "Error" }

Correct examples and test cases

Variable only used for assignment

NR == 1 {a  = 1}
NR == 1000 {a  = 2}
END { if (a != 2) print "Error" }

Variable only used for accumulation

NR == 1 {a += 1}
NR == 1000 {a += 2}
NR == 2000 {a++}
NR == 3000 {a--}
NR == 4000 {++a}
END { if (a != 4) print "Error" }

Variable used only within the same record

{ a = $1; if (a) k++ }

Using a variable on the same record

!a  { a = $2 }
{ a = min(a, $2) }

Motivating example: descriptive statistics

!min_value { min_value = $1}
!max_value { max_value = $1}
{ 
  n++
  sum += $1
  min_value = min(min_value, $1)
  max_value = max(max_value, $1)
}
END { print "count=", n, "min=", min_value, "max=", max_value, "avg=", sum / n }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions