Академический Документы
Профессиональный Документы
Культура Документы
Languages/Grammars
← Programming Language Paradigms · Parsing →
T is a set of tokens. Tokens form the vocabulary of the language and are the smallest units of
syntax. These elements are the symbols that programmers see when they are typing their code,
e.g., the while's, for's, +'s, ('s, etc.
N is a set of nonterminals. Nonterminals are not part of the language per se. Rather, they help to
determine the structure of the derivation trees that can be derived from the grammar. Usually we
enclose these symbols in angle brackets, to distinguish them from the terminals.
P is a set of productions rules. Each production is composed of a left-hand side, a separator and
a right-hand side, e.g., <non-terminal> := <expr1> ... <exprN>, where ':=' is the separator. For
convenience, productions with the same left-hand side can be abbreviated using the symbol '|'.
The pipe, in this case, is used to separate different alternatives.
S is a start symbol. Any sequence of derivations that ultimately produces a grammatically valid
program starts from this special non-terminal.
As an example, below we have a very simple grammar, that recognizes arithmetic expressions. In
other words, any program in this simple language represents the product or the sum of names such
as 'a', 'b' and 'c'.
<exp> ::= <exp> "+" <exp>
<exp> ::= <exp> "*" <exp>
<exp> ::= "(" <exp> ")"
<exp> ::= "a"
<exp> ::= "b"
<exp> ::= "c"
This grammar could be also represented in a more convenient way using a sequence of bar
symbols, e.g.:
<exp> ::= <exp> "+" <exp> | <exp> "*" <exp> | "(" <exp> ")" | "a" | "b" | "c"
Common symbols[edit]
The American National Standards Institute (ANSI) set standards for flowcharts and their symbols in
the 1960s.[14] The International Organization for Standardization (ISO) adopted the ANSI symbols in
1970.[15] The current standard, ISO 5807, was revised in 1985.[16] Generally, flowcharts flow from top
to bottom and left to right.[17]
ANSI/ISO
Name Description
Shape
Other symbols[edit]
The ANSI/ISO standards include symbols beyond the basic shapes. Some are:[17][18]
Data File or
Data represented by a cylinder (disk drive).
Database
Single documents represented a rectangle with a wavy base.
Document
Parallel processing[edit]
Parallel Mode represented by two horizontal lines at the beginning or ending of simultaneous
operations[17]
For parallel and concurrent processing the Parallel Mode horizontal lines[19] or a horizontal
bar[20] indicate the start or end of a section of processes that can be done independently:
At a fork, the process creates one or more additional processes, indicated by a bar with one
incoming path and two or more outgoing paths.
At a join, two or more processes continue as a single process, indicated by a bar with several
incoming paths and one outgoing path. All processes must complete before the single process
continues.[20]
Software[edit]
Diagramming[edit]
Flowgorithm
Any drawing program can be used to create flowchart diagrams, but these will have no underlying
data model to share data with databases or other programs such as project management systems
or spreadsheet. Some tools such as yEd, Inkscape and Microsoft Visio offer special support for
flowchart drawing. Many software packages exist that can create flowcharts automatically, either
directly from a programming language source code, or from a flowchart description language.
There are several applications and visual programming languages[21] that use flowcharts to represent
and execute programs. Generally these are used as teaching tools for beginner students. Examples
include Flowgorithm, Raptor. LARP, Visual Logic, and VisiRule.
Operator Meaning
| Bitwise OR operator
The bitwise logical operators work on the data bit by bit, starting from the least
significant bit, i.e. LSB bit which is the rightmost bit, working towards the MSB
(Most Significant Bit) which is the leftmost bit.
The result of the computation of bitwise logical operators is shown in the table
given below.
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 1 0
Bitwise AND
This is one of the most commonly used logical bitwise operators. It is
represented by a single ampersand sign (&). Two integer expressions are
written on each side of the (&) operator.
The result of the bitwise AND operation is 1 if both the bits have the value as
1; otherwise, the result is always 0.
Let us consider that we have 2 variables op1 and op2 with values as follows:
The result of the AND operation on variables op1 and op2 will be
As we can see, two variables are compared bit by bit. Whenever the value of
a bit in both the variables is 1, then the result will be 1 or else 0.
Bitwise OR
It is represented by a single vertical bar sign (|). Two integer expressions are
written on each side of the (|) operator.
The result of the bitwise OR operation is 1 if at least one of the expression has
the value as 1; otherwise, the result is always 0.
Let us consider that we have 2 variables op1 and op2 with values as follows:
Bitwise Exclusive OR
It is represented by a symbol (^). Two integer expressions are written on each
side of the (^) operator.
Let us consider that we have 2 variables op1 and op2 with values as follows:
As we can see, two variables are compared bit by bit. Whenever only one
variable holds the value 1 then the result is 0 else 0 will be the result.
#include <stdio.h>
int main()
{
int a = 20; /* 20 = 010100 */
int b = 21; /* 21 = 010101 */
int c = 0;
c = a & b; /* 20 = 010100 */
printf("AND - Value of c is %d\n", c );
c = a | b; /* 21 = 010101 */
printf("OR - Value of c is %d\n", c );
c = a ^ b; /* 1 = 0001 */
printf("Exclusive-OR - Value of c is %d\n", c );
getch();
}
Output:
AND - Value of c is 20
OR - Value of c is 21
Exclusive-OR - Value of c is 1
Here,
The left shift operation will shift the 'n' number of bits to the left side. The
leftmost bits in the expression will be popped out, and n bits with the value 0
will be filled on the right side.
The right shift operation will shift the 'n' number of bits to the right side. The
rightmost 'n' bits in the expression will be popped out, and the value 0 will be
filled on the left side.
Shifts operators can be combined then it can be used to extract the data from
the integer expression. Let us write a program to demonstrate the use of
bitwise shift operators.
#include <stdio.h>
int main() {
int a = 20; /* 20 = 010100 */
int c = 0;
c = a << 2; /* 80 = 101000 */
printf("Left shift - Value of c is %d\n", c );
Output:
After performing the left shift operation the value will become 80 whose binary
equivalent is 101000.
After performing the right shift operation, the value will become 5 whose
binary equivalent is 000101.
When we perform complement on any bits, all the 1's become 0's and vice
versa.
#include <stdio.h>
int main() {
int a = 10; /* 10 = 1010 */
int c = 0;
c = ~(a);
printf("Complement - Value of c is %d\n", c );
return 0;
}
Output:
#include <stdio.h>
main() {
unsigned int x = 48; /* 48 = 0011 0000 */
unsigned int y = 13; /* 13 = 0000 1101 */
int z = 0;
z = x | y; /* 61 = 0011 1101 */
printf("Bitwise OR Operator - x | y = %d\n", z );
After we compile and run the program, it produces the following result:
Summary
Bitwise operators are special operator set provided by 'C.'
They are used in bit level programming.
These operators are used to manipulate bits of an integer expression.
Logical, shift and complement are three types of bitwise operators.
Bitwise complement operator is used to reverse the bits of an
expression.
A pointer is a value that designates the address (i.e., the location in memory), of some value.
Pointers are variables that hold a memory location.
There are four fundamental things you need to know about pointers:
How to declare them (with the address operator ' & ': int *pointer = &variable; )
How to assign to them ( pointer = NULL; )
How to reference the value to which the pointer points (known as dereferencing, by using the
dereferencing operator ' * ': value = *pointer; )
How they relate to arrays (the vast majority of arrays in C are simple lists, also called "1
dimensional arrays", but we will briefly cover multi-dimensional arrays with some pointers in a
later chapter).
Pointers can reference any data type, even functions. We'll also discuss the relationship of pointers
with text strings and the more advanced concept of function pointers.
Contents
1Declaring pointers
2Assigning values to pointers
3Pointer dereferencing
4Pointers and Arrays
5Pointers in Function Arguments
6Pointers and Text Strings
7Pointers to Functions
8Practical use of function pointers in C
9Examples of pointer constructs
10sizeof
11External Links
Declaring pointers[edit]
Consider the following snippet of code which declares two pointers:
struct MyStruct {
int m_aNumber;
float num2;
};
int main()
{
int *pJ2;
struct MyStruct *pAnItem;
}
Lines 1-4 define a structure. Line 8 declares a variable which points to an int, and line 9 declares a
variable which points to something with structure MyStruct. So to declare a variable as something
which points to some type, rather than contains some type, the asterisk ( * ) is placed before the
variable name.
In the following, line 1 declares var1 as a pointer to a long and var2 as a long and not a pointer to
a long. In line 2, p3 is declared as a pointer to a pointer to an int.
Pointer types are often used as parameters to function calls. The following shows how to declare a
function which uses a pointer as an argument. Since C passes function arguments by value, in order
to allow a function to modify a value from the calling routine, a pointer to the value must be passed.
Pointers to structures are also used as function arguments even when nothing in the struct will be
modified in the function. This is done to avoid copying the complete contents of the structure onto
the stack. More about pointers as function arguments later.
int myInt;
int *pPointer;
struct MyStruct dvorak;
struct MyStruct *pKeyboard;
pPointer = &myInt;
pKeyboard = &dvorak;
Here, pPointer will now reference myInt and pKeyboard will reference dvorak.
Pointers can also be assigned to reference dynamically allocated memory. The malloc() and calloc()
functions are often used to do this.
#include <stdlib.h>
/* ... */
struct MyStruct *pKeyboard;
/* ... */
pKeyboard = malloc(sizeof *pKeyboard);
The malloc function returns a pointer to dynamically allocated memory (or NULL if unsuccessful).
The size of this memory will be appropriately sized to contain the MyStruct structure.
The following is an example showing one pointer being assigned to another and of a pointer being
assigned a return value from a function.
if (b == 1) myReturn = &val1;
else if (b==2) myReturn = &val2;
else if (b==3) myReturn = &val3;
else myReturn = &val4;
return myReturn;
}
Pointer dereferencing[edit]
To access a value to which a pointer points, the * operator is used. Another operator, the -
> operator is used in conjunction with pointers to structures. Here's a short example.
int c, d;
int *pj;
struct MyStruct astruct;
struct MyStruct *bb;
c = 10;
pj = &c; /* pj points to c */
d = *pj; /* d is assigned the value to which pj points, 10 */
pj = &d; /* now points to d */
*pj = 12; /* d is now 12 */
bb = &astruct;
(*bb).m_aNumber = 3; /* assigns 3 to the m_aNumber member of astruct */
bb->num2 = 44.3; /* assigns 44.3 to the num2 member of astruct */
*pj = bb->m_aNumber; /* equivalent to d = astruct.m_aNumber; */
A variable declared as an array of some type acts as a pointer to that type. When used by itself,
it points to the first element of the array.
A pointer can be indexed like an array name.
The first case often is seen to occur when an array is passed as an argument to a function. The
function declares the parameter as a pointer, but the actual argument may be the name of an array.
The second case often occurs when accessing dynamically allocated memory. Let's look at
examples of each. In the following code, the call to calloc() effectively allocates an array of struct
MyStruct items.
/* ... */
struct MyStruct myArray[4];
#define MY_ARRAY_SIZE (sizeof(myArray)/sizeof(*myArray))
float v3;
struct MyStruct *secondArray;
int someSize;
int ix;
/* initialization of myArray ... */
v3 = KrazyFunction( myArray, MY_ARRAY_SIZE, 4 );
/* ... */
secondArray = calloc( someSize, sizeof(MyStruct) );
for (ix=0; ix<someSize; ix++) {
secondArray[ix].m_aNumber = ix *2;
secondArray[ix].num2 = .304 * ix * ix;
}
Pointers and array names can pretty much be used interchangeably. There are exceptions. You
cannot assign a new pointer value to an array name. The array name will always point to the first
element of the array. In the function KrazyFunction above, you could however assign a new value
to parm1, as it is just a pointer to the first element of myArray. It is also valid for a function to return a
pointer to one of the array elements from an array passed as an argument to a function. A function
should never return a pointer to a local variable, even though the compiler will probably not
complain.
When declaring parameters to functions, declaring an array variable without a size is equivalent to
declaring a pointer. Often this is done to emphasize the fact that the pointer variable will be used in a
manner equivalent to an array.
Now we're ready to discuss pointer arithmetic. You can add and subtract integer values to/from
pointers. If myArray is declared to be some type of array, the expression *(myArray+j) , where j is
an integer, is equivalent to myArray[j] . So for instance in the above example where we had the
expression secondArray[i].num2, we could have written that as *(secondArray+i).num2 or more
simply (secondArray+i)->num2 .
Note that for addition and subtraction of integers and pointers, the value of the pointer is not
adjusted by the integer amount, but is adjusted by the amount multiplied by the size (in bytes) of the
type to which the pointer refers. One pointer may also be subtracted from another, provided they
point to elements of the same array (or the position just beyond the end of the array). If you have a
pointer that points to an element of an array, the index of the element is the result when the array
name is subtracted from the pointer. Here's an example.
.
/* array initialization .. */
.
for (p2 = someArray; p2 < someArray+20; ++p2) {
if (p2->num2 > testValue) break;
}
idx = p2 - someArray;
SECTION 11.6: INTERRUPT PROGRAMMING IN C
So far all the programs in this chapter have been written in Assembly. In this section we
show how to program the 8051/52′s interrupts in 8051 C language. In reading this
section, it is assumed that you already know the material in the first two sections of this
chapter.
8051 C interrupt numbers
The 8051 C compilers have extensive support for the 8051 interrupts with two major
features as follows:
1. They assign a unique number to each of the 8051 interrupts, as shown in Table
11-4.
2. It can also assign a register bank to an ISR. This avoids code overhead due to
the pushes and pops of the RO – R7 registers.
Table 11-4: 8051/52 Interrupt Numbers in C
Example 11-14
Write a C program that continuously gets a single bit of data from PI. 7 and sends it to
Pl.O, while simultanepusly creating a square wave of 200 (as period on pin P2.5. Use
timer 0 to create the square wave. Assume that XTAL = 11.0592 MHz.
Solution:
Example 11-15
Write a C program that continuously gets a single bit of data from PI. 7 and sends it to
Pl.O in the main, while simultaneously (a) creating a square wave of 200 us period on
pin P2.5, and (b) sending letter ‘A’ to the serial port. Use Timer 0 to create the square
wave. Assume that XTAL = 11.0592 MHz. Use the 9600 baud rate.
Solution:
Example 11-16
Write a C program using interrupts to do the following:
1. Receive data serially and send it to PO,
2. Read port PI, transmit data serially, and give a copy to P2,
3. Make timer 0 generate a square wave of 5 kHz frequency on PO.l.
Assume that XTAL = 11.0592 MHz. Set the baud rate at 4800.
Solution:
Example 11-17
Write a C program using interrupts to do the following:
1. Generate a 10000 Hz frequency on P2.1 using TO 8-bit auto-reload,
2. Use timer 1 as an event counter to count up a 1-Hz pulse and display it on PO. The
pulse is connected to EX1.
Assume that XTAL = 11.0592 MHz. Set the baud rate at 9600.
SUMMARY
An interrupt is an external or internal event that interrupts the microcontroller to inform it
that a device needs its service. Every interrupt has a program associated with it called
the ISR, or interrupt service routine. The 8051 has 6 interrupts, 5 of which are user-
accessible. The interrupts- are for reset: two for the timers, two for external hardware
interrupts, and a serial communication interrupt. The 8052 has an additional interrupt for
Timer 2.
The 8051 can be programmed to enable or disable an interrupt, and the interrupt priority
can be altered. This chapter showed how to program 8051/52 interrupts in both
Assembly and C languages.
Types of Files
When dealing with files, there are two types of files you should know about:
1. Text files
2. Binary files
1. Text files
Text files are the normal .txt files that you can easily create using Notepad or any simple
text editors.
When you open those files, you'll see all the contents within the file as plain text. You
can easily edit or delete the contents.
They take minimum effort to maintain, are easily readable, and provide least security
and takes bigger storage space.
2. Binary files
Binary files are mostly the .bin files in your computer.
Instead of storing data in plain text, they store it in the binary form (0's and 1's).
They can hold higher amount of data, are not readable easily and provides a better
security than text files.
File Operations
In C, you can perform four major operations on the file, either text or binary:
FILE *fptr;
ptr = fopen("fileopen","mode")
For Example:
fopen("E:\\cprogram\\newprogram.txt","w");
fopen("E:\\cprogram\\oldprogram.bin","rb");
Let's suppose the file newprogram.txt doesn't exist in the location E:\cprogram. The first
function creates a new file named newprogram.txt and opens it for writing as per the mode 'w'.
The writing mode allows you to create and edit (overwrite) the contents of the file.
Now let's suppose the second binary file oldprogram.bin exists in the location E:\cprogram.
The second function opens the existing file for reading in binary mode 'rb'.
The reading mode only allows you to read the file, you cannot write into the file.
File
Mode Meaning of Mode During Inexistence of file
r Open for reading. If the file does not exist, fopen() returns NULL.
rb Open for reading in binary mode. If the file does not exist, fopen() returns NULL.
r+ Open for both reading and writing. If the file does not exist, fopen() returns NULL.
Open for both reading and writing in If the file exists, its contents are overwritten. If the
wb+ binary mode. file does not exist, it will be created.
a+ Open for both reading and appending. If the file does not exists, it will be created.
Closing a File
The file (both text and binary) should be closed after reading/writing.
After you compile and run this program, you can see a text file program.txt created in C
drive of your computer. When you open the file, you can see the integer you entered.
fwrite(address_data,size_data,numbers_data,pointer_to_file);
Example 3: Write to a binary file using fwrite()
1. #include <stdio.h>
2. #include <stdlib.h>
3.
4. struct threeNum
5. {
6. int n1, n2, n3;
7. };
8.
9. int main()
10. {
11. int n;
12. struct threeNum num;
13. FILE *fptr;
14.
15. if ((fptr = fopen("C:\\program.bin","wb")) == NULL){
16. printf("Error! opening file");
17.
18. // Program exits if the file pointer returns NULL.
19. exit(1);
20. }
21.
22. for(n = 1; n < 5; ++n)
23. {
24. num.n1 = n;
25. num.n2 = 5*n;
26. num.n3 = 5*n + 1;
27. fwrite(&num, sizeof(struct threeNum), 1, fptr);
28. }
29. fclose(fptr);
30.
31. return 0;
32. }
In this program, you create a new file program.bin in the C drive.
We declare a structure threeNum with three numbers - n1, n2 and n3, and define it in the
main function as num.
Now, inside the for loop, we store the value into the file using fwrite().
The first parameter takes the address of num and the second parameter takes the size of
the structure threeNum.
Since, we're only inserting one instance of num, the third parameter is 1. And, the last
parameter *fptr points to the file we're storing the data.
fread(address_data,size_data,numbers_data,pointer_to_file);
This will waste a lot of memory and operation time. An easier way to get to the required
data can be achieved using fseek().
As the name suggests, fseek() seeks the cursor to the given record in the file.
Syntax of fseek()
fseek(FILE * stream, long int offset, int whence)
The first parameter stream is the pointer to the file. The second parameter is the
position of the record to be found, and the third parameter specifies the location where
the offset starts.
Whence Meaning
SEEK_CUR Starts the offset from the current location of the cursor in the file.
Example 5: fseek()
1. #include <stdio.h>
2. #include <stdlib.h>
3.
4. struct threeNum
5. {
6. int n1, n2, n3;
7. };
8.
9. int main()
10. {
11. int n;
12. struct threeNum num;
13. FILE *fptr;
14.
15. if ((fptr = fopen("C:\\program.bin","rb")) == NULL){
16. printf("Error! opening file");
17.
18. // Program exits if the file pointer returns NULL.
19. exit(1);
20. }
21.
22. // Moves the cursor to the end of the file
23. fseek(fptr, -sizeof(struct threeNum), SEEK_END);
24.
25. for(n = 1; n < 5; ++n)
26. {
27. fread(&num, sizeof(struct threeNum), 1, fptr);
28. printf("n1: %d\tn2: %d\tn3: %d\n", num.n1, num.n2, num.n3);
29. fseek(fptr, -2*sizeof(struct threeNum), SEEK_CUR);
30. }
31. fclose(fptr);
32.
33. return 0;
34. }
This program will start reading the records from the file program.bin in the reverse order
(last to first) and prints it.